Skip to content

Commit b2fd494

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 760c504 commit b2fd494

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
@@ -670,12 +670,6 @@ class StdioResultsInput(BaseModel):
670670
...,
671671
description="Full absolute path to the output CSV file (must end in .csv).",
672672
)
673-
output_spreadsheet_title: str | None = Field(
674-
default=None,
675-
description="Create a new Google Sheet with this title and write the full "
676-
"results there. Returns the spreadsheet URL. Fails if a sheet with "
677-
"this exact title already exists — pick a unique name.",
678-
)
679673

680674
@field_validator("task_id")
681675
@classmethod

everyrow-mcp/src/everyrow_mcp/tools.py

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

126126
token = await get_google_token()
127127
async with GoogleSheetsClient(token) as client:
128-
# Guard: check for existing sheets with the same title
129-
existing = await client.list_spreadsheets(query=title, max_results=5)
128+
# Best-effort duplicate guard (TOCTOU race is inherent to the
129+
# Drive API — two concurrent creates can both pass this check).
130+
existing = await client.list_spreadsheets(query=title, max_results=50)
130131
for f in existing:
131132
if f.get("name") == title:
132133
raise ValueError(
@@ -1130,18 +1131,6 @@ async def everyrow_results_stdio(
11301131
)
11311132
]
11321133

1133-
# ── Google Sheets output ─────────────────────────────────────
1134-
if params.output_spreadsheet_title:
1135-
try:
1136-
return await _write_results_to_sheet(df, params.output_spreadsheet_title)
1137-
except Exception as e:
1138-
return [
1139-
TextContent(
1140-
type="text",
1141-
text=f"Failed to write results to Google Sheet: {e!r}",
1142-
)
1143-
]
1144-
11451134
output_file = Path(params.output_path)
11461135
save_result_to_csv(df, output_file)
11471136
artifact_line = f"\nOutput artifact_id: {artifact_id}" if artifact_id else ""

everyrow-mcp/tests/test_stdio_content.py

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

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

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

0 commit comments

Comments
 (0)