spreadsheet_read_mcp/
model.rs

1use crate::caps::BackendCaps;
2use schemars::JsonSchema;
3use serde::{Deserialize, Serialize};
4use std::collections::BTreeMap;
5
6#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
7#[serde(transparent)]
8pub struct WorkbookId(pub String);
9
10impl WorkbookId {
11    pub fn as_str(&self) -> &str {
12        &self.0
13    }
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
17pub struct WorkbookDescriptor {
18    pub workbook_id: WorkbookId,
19    pub short_id: String,
20    pub slug: String,
21    pub folder: Option<String>,
22    pub path: String,
23    pub bytes: u64,
24    pub last_modified: Option<String>,
25    pub caps: BackendCaps,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
29pub struct WorkbookListResponse {
30    pub workbooks: Vec<WorkbookDescriptor>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
34pub struct WorkbookDescription {
35    pub workbook_id: WorkbookId,
36    pub short_id: String,
37    pub slug: String,
38    pub path: String,
39    pub bytes: u64,
40    pub sheet_count: usize,
41    pub defined_names: usize,
42    pub tables: usize,
43    pub macros_present: bool,
44    pub last_modified: Option<String>,
45    pub caps: BackendCaps,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
49pub struct SheetSummary {
50    pub name: String,
51    pub visible: bool,
52    pub row_count: u32,
53    pub column_count: u32,
54    pub non_empty_cells: u32,
55    pub formula_cells: u32,
56    pub cached_values: u32,
57    pub classification: SheetClassification,
58    pub style_tags: Vec<String>,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
62#[serde(rename_all = "snake_case")]
63pub enum SheetClassification {
64    Data,
65    Calculator,
66    Mixed,
67    Metadata,
68    Empty,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
72pub struct SheetListResponse {
73    pub workbook_id: WorkbookId,
74    pub workbook_short_id: String,
75    pub sheets: Vec<SheetSummary>,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
79pub struct SheetOverviewResponse {
80    pub workbook_id: WorkbookId,
81    pub workbook_short_id: String,
82    pub sheet_name: String,
83    pub narrative: String,
84    pub regions: Vec<SheetRegion>,
85    pub key_ranges: Vec<String>,
86    pub formula_ratio: f32,
87    pub notable_features: Vec<String>,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
91pub struct SheetRegion {
92    pub kind: RegionKind,
93    pub address: String,
94    pub description: String,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
98#[serde(rename_all = "snake_case")]
99pub enum RegionKind {
100    Table,
101    Calculator,
102    Metadata,
103    Styles,
104    Comments,
105    Other,
106}
107
108#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
109pub struct SheetPageResponse {
110    pub workbook_id: WorkbookId,
111    pub workbook_short_id: String,
112    pub sheet_name: String,
113    pub rows: Vec<RowSnapshot>,
114    pub has_more: bool,
115    pub next_start_row: Option<u32>,
116    pub header_row: Option<RowSnapshot>,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
120pub struct RowSnapshot {
121    pub row_index: u32,
122    pub cells: Vec<CellSnapshot>,
123}
124
125#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
126pub struct CellSnapshot {
127    pub address: String,
128    pub value: Option<CellValue>,
129    pub formula: Option<String>,
130    pub cached_value: Option<CellValue>,
131    pub number_format: Option<String>,
132    pub style_tags: Vec<String>,
133    pub notes: Vec<String>,
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
137#[serde(tag = "kind", content = "value")]
138pub enum CellValue {
139    Text(String),
140    Number(f64),
141    Bool(bool),
142    Error(String),
143    Date(String),
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
147pub struct SheetStatisticsResponse {
148    pub workbook_id: WorkbookId,
149    pub workbook_short_id: String,
150    pub sheet_name: String,
151    pub row_count: u32,
152    pub column_count: u32,
153    pub density: f32,
154    pub numeric_columns: Vec<ColumnSummary>,
155    pub text_columns: Vec<ColumnSummary>,
156    pub null_counts: BTreeMap<String, u32>,
157    pub duplicate_warnings: Vec<String>,
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
161pub struct ColumnSummary {
162    pub header: Option<String>,
163    pub column: String,
164    pub samples: Vec<CellValue>,
165    pub min: Option<f64>,
166    pub max: Option<f64>,
167    pub mean: Option<f64>,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
171pub struct SheetFormulaMapResponse {
172    pub workbook_id: WorkbookId,
173    pub workbook_short_id: String,
174    pub sheet_name: String,
175    pub groups: Vec<FormulaGroup>,
176    pub truncated: bool,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
180pub struct FormulaGroup {
181    pub fingerprint: String,
182    pub addresses: Vec<String>,
183    pub formula: String,
184    pub is_array: bool,
185    pub is_shared: bool,
186    pub is_volatile: bool,
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
190pub struct FormulaTraceResponse {
191    pub workbook_id: WorkbookId,
192    pub workbook_short_id: String,
193    pub sheet_name: String,
194    pub origin: String,
195    pub direction: TraceDirection,
196    pub layers: Vec<TraceLayer>,
197    pub next_cursor: Option<TraceCursor>,
198    pub notes: Vec<String>,
199}
200
201#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
202pub struct FormulaTraceEdge {
203    pub from: String,
204    pub to: String,
205    pub formula: Option<String>,
206    pub note: Option<String>,
207}
208
209#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
210pub struct TraceLayer {
211    pub depth: u32,
212    pub summary: TraceLayerSummary,
213    pub highlights: TraceLayerHighlights,
214    pub edges: Vec<FormulaTraceEdge>,
215    pub has_more: bool,
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
219pub struct TraceLayerSummary {
220    pub total_nodes: usize,
221    pub formula_nodes: usize,
222    pub value_nodes: usize,
223    pub blank_nodes: usize,
224    pub external_nodes: usize,
225    pub unique_formula_groups: usize,
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
229pub struct TraceLayerHighlights {
230    pub top_ranges: Vec<TraceRangeHighlight>,
231    pub top_formula_groups: Vec<TraceFormulaGroupHighlight>,
232    pub notable_cells: Vec<TraceCellHighlight>,
233}
234
235#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
236pub struct TraceRangeHighlight {
237    pub start: String,
238    pub end: String,
239    pub count: usize,
240    pub literals: usize,
241    pub formulas: usize,
242    pub blanks: usize,
243    pub sample_values: Vec<CellValue>,
244    pub sample_formulas: Vec<String>,
245    pub sample_addresses: Vec<String>,
246}
247
248#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
249pub struct TraceFormulaGroupHighlight {
250    pub fingerprint: String,
251    pub formula: String,
252    pub count: usize,
253    pub sample_addresses: Vec<String>,
254}
255
256#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
257pub struct TraceCellHighlight {
258    pub address: String,
259    pub kind: TraceCellKind,
260    pub value: Option<CellValue>,
261    pub formula: Option<String>,
262}
263
264#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
265#[serde(rename_all = "snake_case")]
266pub enum TraceCellKind {
267    Formula,
268    Literal,
269    Blank,
270    External,
271}
272
273#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
274pub struct TraceCursor {
275    pub depth: u32,
276    pub offset: usize,
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
280#[serde(rename_all = "snake_case")]
281pub enum TraceDirection {
282    Precedents,
283    Dependents,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
287pub struct NamedRangeDescriptor {
288    pub name: String,
289    pub scope: Option<String>,
290    pub refers_to: String,
291    pub kind: NamedItemKind,
292    pub sheet_name: Option<String>,
293    pub comment: Option<String>,
294}
295
296#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
297#[serde(rename_all = "snake_case")]
298pub enum NamedItemKind {
299    NamedRange,
300    Table,
301    Formula,
302    Unknown,
303}
304
305#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
306pub struct NamedRangesResponse {
307    pub workbook_id: WorkbookId,
308    pub workbook_short_id: String,
309    pub items: Vec<NamedRangeDescriptor>,
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
313pub struct FindFormulaMatch {
314    pub address: String,
315    pub sheet_name: String,
316    pub formula: String,
317    pub cached_value: Option<CellValue>,
318    pub context: Vec<RowSnapshot>,
319}
320
321#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
322pub struct FindFormulaResponse {
323    pub workbook_id: WorkbookId,
324    pub workbook_short_id: String,
325    pub matches: Vec<FindFormulaMatch>,
326}
327
328#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
329pub struct VolatileScanEntry {
330    pub address: String,
331    pub sheet_name: String,
332    pub function: String,
333    pub note: Option<String>,
334}
335
336#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
337pub struct VolatileScanResponse {
338    pub workbook_id: WorkbookId,
339    pub workbook_short_id: String,
340    pub items: Vec<VolatileScanEntry>,
341    pub truncated: bool,
342}
343
344#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
345pub struct SheetStylesResponse {
346    pub workbook_id: WorkbookId,
347    pub workbook_short_id: String,
348    pub sheet_name: String,
349    pub styles: Vec<StyleSummary>,
350    pub conditional_rules: Vec<String>,
351}
352
353#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
354pub struct StyleSummary {
355    pub style_id: String,
356    pub occurrences: u32,
357    pub tags: Vec<String>,
358    pub example_cells: Vec<String>,
359}
360
361#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
362pub struct ManifestStubResponse {
363    pub workbook_id: WorkbookId,
364    pub workbook_short_id: String,
365    pub slug: String,
366    pub sheets: Vec<ManifestSheetStub>,
367}
368
369#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
370pub struct ManifestSheetStub {
371    pub sheet_name: String,
372    pub classification: SheetClassification,
373    pub candidate_expectations: Vec<String>,
374    pub notes: Vec<String>,
375}
376
377#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
378pub struct CloseWorkbookResponse {
379    pub workbook_id: WorkbookId,
380    pub message: String,
381}