Skip to content

Commit e2216b0

Browse files
RafaelPoclaude
andcommitted
Fix stdio sheets bug: remove output_spreadsheet_title from StdioResultsInput
output_spreadsheet_title requires Google OAuth tokens which are only available in HTTP mode. Exposing it in stdio mode caused the function to attempt a Google API call, fail, and return early without writing the CSV — silently breaking the tool's primary functionality. Also bump duplicate-sheet guard from max_results=5 to 50 and document the inherent TOCTOU race condition. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent fcd486c commit e2216b0

3 files changed

Lines changed: 6 additions & 23 deletions

File tree

everyrow-mcp/src/everyrow_mcp/models.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -530,12 +530,6 @@ class StdioResultsInput(BaseModel):
530530
...,
531531
description="Full absolute path to the output CSV file (must end in .csv).",
532532
)
533-
output_spreadsheet_title: str | None = Field(
534-
default=None,
535-
description="Create a new Google Sheet with this title and write the full "
536-
"results there. Returns the spreadsheet URL. Fails if a sheet with "
537-
"this exact title already exists — pick a unique name.",
538-
)
539533

540534
@field_validator("task_id")
541535
@classmethod

everyrow-mcp/src/everyrow_mcp/tools.py

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,9 @@ async def _write_results_to_sheet(
116116

117117
token = await get_google_token()
118118
async with GoogleSheetsClient(token) as client:
119-
# Guard: check for existing sheets with the same title
120-
existing = await client.list_spreadsheets(query=title, max_results=5)
119+
# Best-effort duplicate guard (TOCTOU race is inherent to the
120+
# Drive API — two concurrent creates can both pass this check).
121+
existing = await client.list_spreadsheets(query=title, max_results=50)
121122
for f in existing:
122123
if f.get("name") == title:
123124
raise ValueError(
@@ -876,18 +877,6 @@ async def everyrow_results_stdio(
876877
)
877878
]
878879

879-
# ── Google Sheets output ─────────────────────────────────────
880-
if params.output_spreadsheet_title:
881-
try:
882-
return await _write_results_to_sheet(df, params.output_spreadsheet_title)
883-
except Exception as e:
884-
return [
885-
TextContent(
886-
type="text",
887-
text=f"Failed to write results to Google Sheet: {e!r}",
888-
)
889-
]
890-
891880
output_file = Path(params.output_path)
892881
save_result_to_csv(df, output_file)
893882
return [

everyrow-mcp/tests/test_stdio_content.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -584,10 +584,10 @@ def test_http_results_schema_includes_output_spreadsheet_title(self):
584584
schema = HttpResultsInput.model_json_schema()
585585
assert "output_spreadsheet_title" in schema["properties"]
586586

587-
def test_stdio_results_schema_includes_output_spreadsheet_title(self):
588-
"""StdioResultsInput schema includes output_spreadsheet_title for Google Sheets export."""
587+
def test_stdio_results_schema_excludes_output_spreadsheet_title(self):
588+
"""StdioResultsInput must not expose output_spreadsheet_title (requires HTTP OAuth)."""
589589
schema = StdioResultsInput.model_json_schema()
590-
assert "output_spreadsheet_title" in schema["properties"]
590+
assert "output_spreadsheet_title" not in schema["properties"]
591591

592592
@pytest.mark.parametrize(
593593
"tool_name,def_name",

0 commit comments

Comments
 (0)