Skip to content

Collapse phantom progress beats across MCP tools#391

Merged
akolotov merged 12 commits into
mainfrom
claude/musing-ardinghelli-d0fcab
Jun 3, 2026
Merged

Collapse phantom progress beats across MCP tools#391
akolotov merged 12 commits into
mainfrom
claude/musing-ardinghelli-d0fcab

Conversation

@akolotov
Copy link
Copy Markdown
Collaborator

@akolotov akolotov commented Jun 3, 2026

Closes #385

Summary

Implements honest progress reporting across the MCP tools. Several tools were emitting phantom progress beats — e.g. a "Fetching data…" beat that fired instantly with no real work behind it, and total scales that overstated the number of operations. This made progress fractions misleading and, in some branches, produced messages that were outright false (e.g. claiming data was "fetched" on a path where the fetch had failed).

The fix collapses each tool's progress to a count that reflects the real operations performed: single-fetch tools report total=1.0 (start → completion), and tools with a genuine fetch-to-process watershed report total=2.0 (start → watershed → completion). Watershed messages on multi-request paths were reworded to be neutral ("… requests completed; processing results.") so they stay truthful regardless of which underlying request failed.

What changed

  • Single-fetch tools collapsed to total=1.0 (phantom beat removed): get_tokens_by_address, nft_tokens_by_address, lookup_token_by_symbol, get_transaction_info, get_contract_abi, inspect_contract_code (DD-02), direct_api_call (DD-01, with an enriched start message naming the method/endpoint/chain and a (next page) suffix).
  • Advanced-filter transaction tools collapsed (phantom pre-fetch beat removed): get_transactions_by_address and get_token_transfers_by_address dropped the instant "Fetching…" beat that lingered after Switch to PRO API #384 moved URL resolution into the request helper (leaving two report_and_log_progress calls back-to-back). Step counts were rescaled to the real operations — transactions total 12→11 with the first page now step 1 (10 pages + final completion); token transfers total 2→1 — and the smart-pagination helper defaults (progress_start_step, total_steps) updated to match. The periodic-progress mechanism already emits a real beat in the ~1.0 region, so no gap is introduced. These two were the remaining gap behind the "across MCP tools" claim.
  • inspect_contract_code completion message neutralized: "Successfully fetched contract data." → "Contract data ready.", so the completion beat stays truthful on a cache hit (where _fetch_and_process_contract returns cached data and no network fetch occurs).
  • Branch-sensitive collapse for block tools: get_block_number and get_block_info now scale total per branch (latest vs. by-datetime; with/without transactions) and emit honest counts on each path.
  • get_address_info slimmed while keeping its real fetch-to-process watershed (DD-03), with a neutralized watershed message.
  • Helper cleanup: _fetch_and_process_contract is now progress-free (the calling tool owns the beats); inline imports hoisted to module top.
  • Docs: SPEC.md progress convention rewritten to describe the honest beat model and split into a readable nested list; .cursor/rules/110-new-mcp-tool.mdc example updated. .cursor/AGENTS.md and mcpb/manifest.json intentionally left unchanged.
  • Version bumped to 0.16.0.dev13 (pyproject.toml, blockscout_mcp_server/__init__.py, server.json).

Reviewer notes

  • Each commit is one phase of the implementation plan and was independently verified for plan correspondence before committing.
  • Test assertions were updated to encode the new honest beat counts derived from the code (await-counts, per-beat total, and watershed/completion message indices) — no tests were skipped, xfailed, deleted, or loosened.
  • DD-03 is fully implemented in the block/address phases; no follow-up issue is needed.
  • The advanced-filter collapse, the inspect_contract_code message, and the SPEC list reformat were added during review (commit 662e7e2) to close the "across MCP tools" gap.

Verification

  • Full default unit suite: 628 passed, 93 deselected (re-confirmed after the follow-up changes).
  • ruff check . and ruff format --check .: clean.
  • Integration tests at the original phases: 71 passed, 0 failed, 0 skipped, 0 timed out (via the timeout-protected runner). The follow-up changes are unit-level progress-reporting tweaks and do not alter network behavior, so the integration surface is unaffected.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Improved consistency in progress reporting across blockchain data retrieval operations with simplified, clearer start/completion workflows.
  • Bug Fixes

    • Enhanced progress reporting accuracy by reducing unnecessary intermediate updates and aligning reporting patterns across all data fetch operations.
  • Chores

    • Version bumped to 0.16.0.dev13.
    • Updated internal progress reporting logic and specifications for standardized operational clarity.

akolotov and others added 8 commits June 3, 2026 11:24
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

Warning

Review limit reached

@akolotov, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 36 minutes and 22 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a664173f-4fb5-41e7-8f9e-e9a198bba34b

📥 Commits

Reviewing files that changed from the base of the PR and between 232ad42 and b986585.

📒 Files selected for processing (6)
  • .cursor/rules/110-new-mcp-tool.mdc
  • SPEC.md
  • blockscout_mcp_server/__init__.py
  • blockscout_mcp_server/tools/direct_api/direct_api_call.py
  • pyproject.toml
  • server.json

Walkthrough

This PR refactors MCP tool progress reporting to adopt an honest beat model: the number of progress steps now reflects actual distinct awaited operations, eliminating phantom intermediate steps introduced during the PRO API migration. Single-fetch tools report only start/completion on total=1.0; multi-step tools adjust their totals and remove unnecessary beats. The contract helper loses Context dependency, direct_api_call gains path validation and cursor messaging, and all tests align accordingly.

Changes

Progress Model Honest Reporting

Layer / File(s) Summary
Documentation and specification updates
SPEC.md, .cursor/rules/110-new-mcp-tool.mdc
Updated specification to define honest progress model: start beat before chain validation, beats only for genuinely distinct awaited operations, optional watershed beat for concurrent fetches, and 15-second periodic updates independent of the beat count convention. Cursor rules example now shows single-fetch tools with start/completion on total=1.0.
Contract helper refactoring
blockscout_mcp_server/tools/contract/_shared.py, blockscout_mcp_server/tools/contract/get_contract_abi.py, blockscout_mcp_server/tools/contract/inspect_contract_code.py
Removed Context parameter from _fetch_and_process_contract and its progress-reporting calls; moved _truncate_constructor_args import to module scope; updated callers to omit ctx argument while moving progress reporting up to the caller layer.
Single-fetch tools: start/completion on total=1.0
blockscout_mcp_server/tools/address/get_tokens_by_address.py, blockscout_mcp_server/tools/address/nft_tokens_by_address.py, blockscout_mcp_server/tools/search/lookup_token_by_symbol.py, blockscout_mcp_server/tools/transaction/get_token_transfers_by_address.py
Simplified progress reporting to two-beat sequences (0.0/1.0 on total=1.0) by removing intermediate "Fetching data..." steps and collapsing formerly two-step flows into a single fetch operation with start and completion messages.
Multi-step tools: adjusted progress totals and beats
blockscout_mcp_server/tools/address/get_address_info.py, blockscout_mcp_server/tools/block/get_block_info.py, blockscout_mcp_server/tools/block/get_block_number.py, blockscout_mcp_server/tools/transaction/get_transaction_info.py, blockscout_mcp_server/tools/transaction/get_transactions_by_address.py, blockscout_mcp_server/tools/transaction/_shared.py
Updated progress totals and beat sequences: reduced total_steps values, removed phantom intermediate steps, added "watershed" milestone messages for concurrent operations, and adjusted smart-pagination defaults from 2.0/12.0 to 1.0/11.0 to account for actual phases.
direct_api_call: path validation, cursor suffix, progress accounting
blockscout_mcp_server/tools/direct_api/direct_api_call.py
Added earlier endpoint_path normalization (trailing slash stripping), query-string validation raising ValueError if ? is present, updated initial progress message to include HTTP method/path/chain id with optional (next page) suffix when cursor is provided, and adjusted progress/total accounting in both handler-dispatch and completion branches.
Test updates for all affected tools
tests/tools/address/test_*.py, tests/tools/block/test_*.py, tests/tools/contract/test_*.py, tests/tools/search/test_*.py, tests/tools/transaction/test_*.py
Reduced expected progress and info call counts across all tool tests; validated new message content, progress values, and total values; adjusted smart-pagination test parameters to expect 1.0/11.0 instead of 2.0/12.0; updated contract helper invocations to omit ctx argument; verified watershed messages and exact progress sequences.
New direct_api_call progress-focused tests
tests/tools/direct_api/test_direct_api_call_progress.py
Added comprehensive new test module verifying start message includes method/endpoint/chain id, cursor appends (next page) suffix, oversized responses emit both start and completion beats before error, and query strings with secrets are rejected with zero progress beats and no info logs containing ? or SECRET.
Version bumps
blockscout_mcp_server/__init__.py, pyproject.toml, server.json
Incremented package version from 0.16.0.dev11 to 0.16.0.dev12 across package metadata and server configuration files.

Possibly related PRs

  • blockscout/mcp-server#364: Modifies direct_api_call.py to add POST+JSON-body support; overlaps with this PR's cursor/pagination handling and progress accounting adjustments.
  • blockscout/mcp-server#384: Adjusts progress beats during PRO API migration; both PRs modify progress-reporting sequences in the same tools, with this PR extending that work to normalize beat counts across single-fetch and multi-step patterns.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Collapse phantom progress beats across MCP tools' directly and clearly describes the main change: removing misleading intermediate progress beats to align with actual awaited operations.
Linked Issues check ✅ Passed The PR comprehensively addresses all objectives from issue #385: single-fetch tools now report total=1.0 (start/completion only), multi-step tools preserve accurate step counts, progress messages now contextualize in start beats rather than empty intermediate beats, documentation updated, and version bumped.
Out of Scope Changes check ✅ Passed All changes are in-scope: progress-reporting adjustments across tools to match honest operation counts, documentation updates (SPEC.md, cursor rule), version bumps, and test updates reflect the core PR objective. No unrelated refactoring or feature additions detected.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/musing-ardinghelli-d0fcab

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@akolotov akolotov changed the title Honest progress reporting: collapse phantom progress beats across MCP tools Collapse phantom progress beats across MCP tools Jun 3, 2026
@akolotov akolotov self-assigned this Jun 3, 2026
akolotov and others added 2 commits June 3, 2026 14:50
get_transactions_by_address and get_token_transfers_by_address still
emitted an instant pre-fetch "Fetching..." beat (phantom since #384 moved
URL resolution into the request helper, leaving two report calls back to
back). Drop that beat and rescale step counts to the real operations:

- transactions: total 12 -> 11, progress_start_step 2 -> 1 (10 pages +
  final completion); the periodic mechanism's first beat now legitimately
  occupies the ~1.0 region.
- token transfers: total 2 -> 1, current_step_number 2 -> 1.
- smart-pagination helper defaults updated to match, with a docstring
  describing the step model.

inspect_contract_code: completion message "Successfully fetched contract
data." -> "Contract data ready." so it stays truthful on a cache hit,
where no network fetch occurs.

SPEC.md: split the dense progress-convention bullet into a readable
nested list (no semantic change).

Tests updated to the new honest beat counts and step numbers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
get_transaction_info does concurrent fetches (gather) followed by
processing, which the SPEC's progress convention describes as a
start -> watershed -> completion (total=2.0) flow. It was reported as
a single-fetch (total=1.0) tool, diverging from get_block_info which
uses the watershed model for the same shape.

Convert it to total=2.0:
- introduce total_steps (no hardcoded literals)
- reposition the post-gather beat as a neutral watershed
  ("... requests completed; processing results.") so it stays truthful
  when the optional user-operations request fails
- add the completion beat before building TransactionInfoData

Tests: success paths now expect 3 beats; failure paths that raise
before the watershed stay at 1; ops-failure path asserts the neutral
watershed message and the completion message.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@akolotov akolotov marked this pull request as ready for review June 3, 2026 23:11
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
blockscout_mcp_server/tools/transaction/get_token_transfers_by_address.py (1)

71-121: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Missing final progress completion beat.

After make_request_with_periodic_progress completes (line 80-90), the tool performs additional processing (transforming items, creating pagination, building the response) but never reports a final completion beat before returning. Other single-fetch tools in this PR explicitly report completion (e.g., get_block_info at line 46-51, get_block_number at line 65-70).

For consistency with the honest progress model, add a final report_and_log_progress call before the return statement.

📊 Proposed fix to add completion beat
     transformed_items = [
         AdvancedFilterItem.model_validate(_transform_advanced_filter_item(item, fields_to_remove))
         for item in sliced_items
     ]
 
+    await report_and_log_progress(
+        ctx,
+        progress=1.0,
+        total=tool_overall_total_steps,
+        message="Successfully fetched and processed token transfers.",
+    )
+
     range_text = f"from {age_from}" if age_to is None else f"from {age_from} to {age_to}"
     content_text = f"Found {len(transformed_items)} token transfers for {address} on chain {chain_id} {range_text}."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@blockscout_mcp_server/tools/transaction/get_token_transfers_by_address.py`
around lines 71 - 121, After processing the Blockscout response but before
returning, add a final report_and_log_progress call to mark completion: call
report_and_log_progress(ctx, progress=tool_overall_total_steps,
total=tool_overall_total_steps, message="Completed fetching token transfers for
{address} on chain {chain_id}.") (use the same ctx, tool_overall_total_steps
variable and include address/chain_id in the message) and place it just before
the build_tool_response(...) return so the tool emits the final completion beat
after transformation/pagination.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@blockscout_mcp_server/tools/transaction/get_token_transfers_by_address.py`:
- Around line 71-121: After processing the Blockscout response but before
returning, add a final report_and_log_progress call to mark completion: call
report_and_log_progress(ctx, progress=tool_overall_total_steps,
total=tool_overall_total_steps, message="Completed fetching token transfers for
{address} on chain {chain_id}.") (use the same ctx, tool_overall_total_steps
variable and include address/chain_id in the message) and place it just before
the build_tool_response(...) return so the tool emits the final completion beat
after transformation/pagination.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a643aed8-611b-458b-9860-8557f59d6dcf

📥 Commits

Reviewing files that changed from the base of the PR and between aeb689b and 232ad42.

📒 Files selected for processing (35)
  • .cursor/rules/110-new-mcp-tool.mdc
  • SPEC.md
  • blockscout_mcp_server/__init__.py
  • blockscout_mcp_server/tools/address/get_address_info.py
  • blockscout_mcp_server/tools/address/get_tokens_by_address.py
  • blockscout_mcp_server/tools/address/nft_tokens_by_address.py
  • blockscout_mcp_server/tools/block/get_block_info.py
  • blockscout_mcp_server/tools/block/get_block_number.py
  • blockscout_mcp_server/tools/contract/_shared.py
  • blockscout_mcp_server/tools/contract/get_contract_abi.py
  • blockscout_mcp_server/tools/contract/inspect_contract_code.py
  • blockscout_mcp_server/tools/direct_api/direct_api_call.py
  • blockscout_mcp_server/tools/search/lookup_token_by_symbol.py
  • blockscout_mcp_server/tools/transaction/_shared.py
  • blockscout_mcp_server/tools/transaction/get_token_transfers_by_address.py
  • blockscout_mcp_server/tools/transaction/get_transaction_info.py
  • blockscout_mcp_server/tools/transaction/get_transactions_by_address.py
  • pyproject.toml
  • server.json
  • tests/tools/address/test_get_address_info.py
  • tests/tools/address/test_get_address_info_metadata.py
  • tests/tools/address/test_get_tokens_by_address.py
  • tests/tools/address/test_nft_tokens_by_address.py
  • tests/tools/block/test_get_block_info.py
  • tests/tools/block/test_get_block_number.py
  • tests/tools/contract/test_fetch_and_process_contract.py
  • tests/tools/contract/test_get_contract_abi.py
  • tests/tools/contract/test_inspect_contract_code.py
  • tests/tools/direct_api/test_direct_api_call.py
  • tests/tools/direct_api/test_direct_api_call_progress.py
  • tests/tools/search/test_lookup_token_by_symbol.py
  • tests/tools/transaction/test_get_token_transfers_by_address.py
  • tests/tools/transaction/test_get_transaction_info.py
  • tests/tools/transaction/test_get_transactions_by_address.py
  • tests/tools/transaction/test_get_transactions_by_address_pagination.py

akolotov and others added 2 commits June 3, 2026 17:34
main already shipped 0.16.0.dev12 via #389 after this branch diverged,
so re-bump to dev13 to keep the dev version monotonic on merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@akolotov akolotov merged commit 2297535 into main Jun 3, 2026
7 checks passed
@akolotov akolotov deleted the claude/musing-ardinghelli-d0fcab branch June 3, 2026 23:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Honest progress-step model for single-fetch tools after PRO API migration

1 participant