Skip to content

Commit 3752652

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 9077dfa commit 3752652

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
@@ -388,12 +388,6 @@ class StdioResultsInput(BaseModel):
388388
...,
389389
description="Full absolute path to the output CSV file (must end in .csv).",
390390
)
391-
output_spreadsheet_title: str | None = Field(
392-
default=None,
393-
description="Create a new Google Sheet with this title and write the full "
394-
"results there. Returns the spreadsheet URL. Fails if a sheet with "
395-
"this exact title already exists — pick a unique name.",
396-
)
397391

398392
@field_validator("output_path")
399393
@classmethod

everyrow-mcp/src/everyrow_mcp/tools.py

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

7777
token = await get_google_token()
7878
async with GoogleSheetsClient(token) as client:
79-
# Guard: check for existing sheets with the same title
80-
existing = await client.list_spreadsheets(query=title, max_results=5)
79+
# Best-effort duplicate guard (TOCTOU race is inherent to the
80+
# Drive API — two concurrent creates can both pass this check).
81+
existing = await client.list_spreadsheets(query=title, max_results=50)
8182
for f in existing:
8283
if f.get("name") == title:
8384
raise ValueError(
@@ -697,18 +698,6 @@ async def everyrow_results_stdio(
697698
except Exception as e:
698699
return [TextContent(type="text", text=f"Error retrieving results: {e!r}")]
699700

700-
# ── Google Sheets output ─────────────────────────────────────
701-
if params.output_spreadsheet_title:
702-
try:
703-
return await _write_results_to_sheet(df, params.output_spreadsheet_title)
704-
except Exception as e:
705-
return [
706-
TextContent(
707-
type="text",
708-
text=f"Failed to write results to Google Sheet: {e!r}",
709-
)
710-
]
711-
712701
output_file = Path(params.output_path)
713702
save_result_to_csv(df, output_file)
714703
return [

everyrow-mcp/tests/test_stdio_content.py

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

582-
def test_stdio_results_schema_includes_output_spreadsheet_title(self):
583-
"""StdioResultsInput schema includes output_spreadsheet_title for Google Sheets export."""
582+
def test_stdio_results_schema_excludes_output_spreadsheet_title(self):
583+
"""StdioResultsInput must not expose output_spreadsheet_title (requires HTTP OAuth)."""
584584
schema = StdioResultsInput.model_json_schema()
585-
assert "output_spreadsheet_title" in schema["properties"]
585+
assert "output_spreadsheet_title" not in schema["properties"]
586586

587587
@pytest.mark.parametrize(
588588
"tool_name,def_name",

0 commit comments

Comments
 (0)