Skip to content

Commit a901d68

Browse files
committed
fix: Align tool names with upstream implementation
- Update examples/README.md to list correct 7 tools - Fix mcp_client_wrapper.py to use upstream tool names: * inject_fuzz_transactions (not inject_transaction) * clear_fuzz_priorities (not clear_priorities) * status, target, show_coverage, reload_corpus, dump_lcov - Mark old test files as skipped (use old tool names): * test_corpus.py - get_corpus_size, inspect_corpus, find_transaction * test_injection.py - inject_transaction (old signature) * test_prioritization.py - prioritize_function * test_read_logs.py - read_logs (commented out in upstream) - Update docstring: 7 active tools (not 9) These tests are preserved for reference but skipped until updated to match upstream API from PR crytic#1502.
1 parent e2b3262 commit a901d68

File tree

6 files changed

+80
-83
lines changed

6 files changed

+80
-83
lines changed

examples/README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,13 @@ class MyEchidnaAgent:
132132

133133
### Available Tools
134134

135-
1. **status** - Get fuzzing metrics
136-
2. **show_coverage** - Get coverage report
137-
3. **target** - Get contract ABI
138-
4. **inject_fuzz_transactions** - Queue transactions
139-
5. **clear_fuzz_priorities** - Reset priorities
140-
6. **get_corpus** - Get current corpus
141-
7. **set_priority** - Set function priority
135+
1. **status** - Get fuzzing campaign status and metrics
136+
2. **show_coverage** - Get coverage report for contracts
137+
3. **target** - Get target contract name and ABI
138+
4. **inject_fuzz_transactions** - Inject transaction sequences to prioritize
139+
5. **clear_fuzz_priorities** - Clear all function priorities
140+
6. **reload_corpus** - Reload corpus from disk
141+
7. **dump_lcov** - Export coverage in LCOV format
142142

143143
### Strategy Ideas
144144

tests/mcp/scripts/mcp_client_wrapper.py

Lines changed: 37 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ class MCPClientV2:
1414
"""
1515
Enhanced MCP client with convenience methods for each tool.
1616
17-
Wraps httpx and provides typed methods for all 9 MCP tools.
17+
Wraps httpx and provides typed methods for all 7 active MCP tools.
18+
Note: read_logs tool exists but is currently commented out in upstream.
1819
"""
1920

2021
def __init__(self, base_url: str = "http://localhost:8080"):
@@ -45,118 +46,82 @@ def _call_tool(self, tool_name: str, parameters: Dict[str, Any]) -> Dict[str, An
4546

4647
# Observability Tools
4748

48-
def call_read_logs(self, max_count: int = 100, since_timestamp: Optional[int] = None) -> Dict[str, Any]:
49+
def call_status(self) -> Dict[str, Any]:
4950
"""
50-
Read event logs from Echidna campaign.
51+
Get fuzzing campaign status and metrics.
5152
52-
Args:
53-
max_count: Maximum number of events to return
54-
since_timestamp: Optional Unix timestamp to filter events
55-
5653
Returns:
57-
{"events": [...], "count": int, "timestamp": int}
54+
Campaign status including corpus size, iterations, coverage, etc.
5855
"""
59-
params = {"max_count": max_count}
60-
if since_timestamp:
61-
params["since_timestamp"] = since_timestamp
62-
return self._call_tool("read_logs", params)
56+
return self._call_tool("status", {})
6357

64-
def call_show_coverage(self) -> Dict[str, Any]:
58+
def call_show_coverage(self, contract: Optional[str] = None) -> Dict[str, Any]:
6559
"""
66-
Get current code coverage statistics.
60+
Get code coverage report for a specific contract.
6761
62+
Args:
63+
contract: Contract name to show coverage for (optional)
64+
6865
Returns:
69-
{"coverage_points": int, "contracts": [...], "timestamp": int}
66+
Coverage report with annotated source code
7067
"""
71-
return self._call_tool("show_coverage", {})
68+
params = {}
69+
if contract:
70+
params["contract"] = contract
71+
return self._call_tool("show_coverage", params)
7272

73-
def call_dump_lcov(self) -> Dict[str, Any]:
73+
def call_target(self) -> Dict[str, Any]:
7474
"""
75-
Dump coverage in LCOV format.
75+
Get target contract name and ABI.
7676
7777
Returns:
78-
{"lcov": str, "contracts": int}
78+
Target contract information with ABI
7979
"""
80-
return self._call_tool("dump_lcov", {})
80+
return self._call_tool("target", {})
8181

82-
def call_get_corpus_size(self) -> Dict[str, Any]:
82+
def call_dump_lcov(self) -> Dict[str, Any]:
8383
"""
84-
Get current corpus size.
84+
Dump coverage in LCOV format.
8585
8686
Returns:
87-
{"corpus_size": int}
88-
"""
89-
return self._call_tool("get_corpus_size", {})
90-
91-
def call_inspect_corpus(self, offset: int = 0, limit: int = 10) -> Dict[str, Any]:
87+
LCOV formatted coverage data
9288
"""
93-
Inspect transactions in corpus with pagination.
94-
95-
Args:
96-
offset: Starting index
97-
limit: Maximum number of transactions to return
98-
99-
Returns:
100-
{"transactions": [...], "total": int, "offset": int, "limit": int}
101-
"""
102-
return self._call_tool("inspect_corpus_transactions", {
103-
"offset": offset,
104-
"limit": limit
105-
})
89+
return self._call_tool("dump_lcov", {})
10690

107-
def call_find_transaction(self, search_query: str) -> Dict[str, Any]:
91+
def call_reload_corpus(self) -> Dict[str, Any]:
10892
"""
109-
Search for transactions in corpus.
93+
Reload corpus from disk without replaying transactions.
11094
111-
Args:
112-
search_query: Function signature or substring to search for
113-
11495
Returns:
115-
{"matches": [...], "count": int}
96+
Status of corpus reload operation
11697
"""
117-
return self._call_tool("find_transaction_in_corpus", {
118-
"search_query": search_query
119-
})
98+
return self._call_tool("reload_corpus", {})
12099

121100
# Control Tools
122101

123-
def call_inject_transaction(self, transactions: List[str]) -> Dict[str, Any]:
102+
def call_inject_fuzz_transactions(self, transactions: str) -> Dict[str, Any]:
124103
"""
125-
Inject custom transactions into fuzzing campaign.
104+
Inject transaction sequence to prioritize during fuzzing.
126105
127106
Args:
128-
transactions: List of Solidity-like function call strings
129-
e.g., ["transfer(0x123..., 100)", "approve(0x456..., 50)"]
107+
transactions: Newline-separated transaction sequence
108+
e.g., "transfer(0x123..., 100)\\nmint(1000, 0x456...)"
130109
131110
Returns:
132-
{"injected": bool, "transaction_count": int, "worker_id": int}
111+
Status of injection operation
133112
"""
134-
return self._call_tool("inject_transaction", {
113+
return self._call_tool("inject_fuzz_transactions", {
135114
"transactions": transactions
136115
})
137116

138-
def call_prioritize_function(self, function_signature: str) -> Dict[str, Any]:
139-
"""
140-
Set priority for a specific function signature.
141-
142-
Args:
143-
function_signature: Function signature to prioritize (e.g., "balanceOf(address)")
144-
145-
Returns:
146-
{"prioritized": bool, "function_signature": str, "worker_ids": [int]}
147-
"""
148-
return self._call_tool("prioritize_function", {
149-
"function_signature": function_signature
150-
})
151-
152-
def call_clear_priorities(self) -> Dict[str, Any]:
117+
def call_clear_fuzz_priorities(self) -> Dict[str, Any]:
153118
"""
154119
Clear all function prioritization.
155120
156121
Returns:
157-
{"cleared": bool, "worker_ids": [int]}
122+
Status of clear operation
158123
"""
159-
return self._call_tool("clear_priorities", {})
124+
return self._call_tool("clear_fuzz_priorities", {})
160125

161126
def list_tools(self) -> Dict[str, Any]:
162127
"""

tests/mcp/test_corpus.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,19 @@
33
Feature: 001-mcp-agent-commands
44
Phase 5, Task T060
55
6-
Tests for corpus inspection MCP tools.
6+
NOTE: These tests are for corpus inspection tools (get_corpus_size, inspect_corpus_transactions,
7+
find_transaction_in_corpus) which do not exist in the upstream implementation.
8+
The upstream only provides: status, target, reload_corpus, dump_lcov, inject_fuzz_transactions,
9+
clear_fuzz_priorities, show_coverage.
10+
11+
These tests are preserved for reference but skipped.
712
"""
813

914
import pytest
1015
import time
1116

1217

18+
@pytest.mark.skip(reason="get_corpus_size tool does not exist in upstream")
1319
def test_get_corpus_size(mcp_client, echidna_campaign_running):
1420
"""Test that corpus size > 0 after campaign runs."""
1521
# Wait for campaign to generate some corpus
@@ -24,6 +30,7 @@ def test_get_corpus_size(mcp_client, echidna_campaign_running):
2430
print(f"Corpus size after 3s: {result['corpus_size']}")
2531

2632

33+
@pytest.mark.skip(reason="Tool does not exist in upstream")
2734
def test_inspect_corpus_pagination(mcp_client, echidna_campaign_running):
2835
"""Test that pagination parameters work correctly."""
2936
# Wait for corpus to populate
@@ -59,6 +66,7 @@ def test_inspect_corpus_pagination(mcp_client, echidna_campaign_running):
5966
"Different pages should return different transactions"
6067

6168

69+
@pytest.mark.skip(reason="Tool does not exist in upstream")
6270
def test_find_transaction_in_corpus(mcp_client):
6371
"""Test finding a transaction by signature."""
6472
# First inject a known transaction
@@ -81,6 +89,7 @@ def test_find_transaction_in_corpus(mcp_client):
8189
assert "count" in search_result
8290

8391

92+
@pytest.mark.skip(reason="Tool does not exist in upstream")
8493
def test_inspect_corpus_empty_params(mcp_client):
8594
"""Test inspect_corpus with default parameters."""
8695
result = mcp_client.call_tool("inspect_corpus_transactions", {})
@@ -90,6 +99,7 @@ def test_inspect_corpus_empty_params(mcp_client):
9099
assert isinstance(result["transactions"], list)
91100

92101

102+
@pytest.mark.skip(reason="Tool does not exist in upstream")
93103
def test_find_transaction_case_insensitive(mcp_client):
94104
"""Test that search is case-insensitive."""
95105
# Search with lowercase

tests/mcp/test_injection.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
Feature: 001-mcp-agent-commands
44
Phase 5, Task T061
55
6-
Tests for inject_transaction MCP tool.
6+
NOTE: These tests use old tool name 'inject_transaction' but upstream uses 'inject_fuzz_transactions'.
7+
The tool signature is also different - upstream takes a string (newline-separated), not a list.
8+
Tests are skipped until updated to match upstream API.
79
"""
810

911
import pytest
1012
import time
1113

1214

15+
@pytest.mark.skip(reason="Tool name/signature mismatch - upstream uses inject_fuzz_transactions with string parameter")
16+
@pytest.mark.skip(reason="Tool name/signature mismatch with upstream")
1317
def test_inject_single_transaction(mcp_client):
1418
"""Test injecting a valid Solidity syntax transaction."""
1519
result = mcp_client.call_tool("inject_transaction", {
@@ -23,6 +27,7 @@ def test_inject_single_transaction(mcp_client):
2327
assert "worker_id" in result
2428

2529

30+
@pytest.mark.skip(reason="Tool name/signature mismatch with upstream")
2631
def test_inject_multiple_transactions(mcp_client):
2732
"""Test injecting multiple transactions at once."""
2833
transactions = [
@@ -39,6 +44,7 @@ def test_inject_multiple_transactions(mcp_client):
3944
assert result["transaction_count"] == 3
4045

4146

47+
@pytest.mark.skip(reason="Tool name/signature mismatch with upstream")
4248
def test_inject_invalid_transaction(mcp_client):
4349
"""Test injecting malformed input."""
4450
with pytest.raises(RuntimeError) as exc_info:
@@ -49,6 +55,7 @@ def test_inject_invalid_transaction(mcp_client):
4955
assert "error" in str(exc_info.value).lower() or "MCP tool error" in str(exc_info.value)
5056

5157

58+
@pytest.mark.skip(reason="Tool name/signature mismatch with upstream")
5259
def test_inject_empty_list(mcp_client):
5360
"""Test injecting empty transaction list."""
5461
result = mcp_client.call_tool("inject_transaction", {
@@ -61,6 +68,7 @@ def test_inject_empty_list(mcp_client):
6168

6269

6370
@pytest.mark.timeout(1)
71+
@pytest.mark.skip(reason="Tool name/signature mismatch with upstream")
6472
def test_inject_response_time(mcp_client):
6573
"""Test that inject_transaction responds within 100ms."""
6674
times = []
@@ -82,6 +90,7 @@ def test_inject_response_time(mcp_client):
8290
assert mean_time < 100, f"Mean response time {mean_time:.2f}ms exceeds 100ms"
8391

8492

93+
@pytest.mark.skip(reason="Tool name/signature mismatch with upstream")
8594
def test_inject_with_different_argument_types(mcp_client):
8695
"""Test injecting transactions with different argument types."""
8796
transactions = [

tests/mcp/test_prioritization.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@
33
Feature: 001-mcp-agent-commands
44
Phase 5, Task T062
55
6-
Tests for prioritize_function and clear_priorities MCP tools.
6+
NOTE: These tests use old tool names 'prioritize_function' and 'clear_priorities'.
7+
Upstream uses 'inject_fuzz_transactions' (to inject sequences) and 'clear_fuzz_priorities'.
8+
The prioritize_function tool does not exist in upstream - prioritization happens via injection.
9+
Tests are skipped until updated to match upstream API.
710
"""
811

912
import pytest
1013
import time
1114
from collections import Counter
1215

1316

17+
@pytest.mark.skip(reason="Tool does not exist in upstream")
1418
def test_prioritize_function(mcp_client, echidna_campaign_running):
1519
"""Test setting priority for a function."""
1620
result = mcp_client.call_tool("prioritize_function", {
@@ -25,6 +29,7 @@ def test_prioritize_function(mcp_client, echidna_campaign_running):
2529
assert isinstance(result["worker_ids"], list)
2630

2731

32+
@pytest.mark.skip(reason="Tool does not exist in upstream")
2833
def test_clear_priorities(mcp_client):
2934
"""Test clearing all function priorities."""
3035
# First set a priority
@@ -41,6 +46,7 @@ def test_clear_priorities(mcp_client):
4146
assert isinstance(result["worker_ids"], list)
4247

4348

49+
@pytest.mark.skip(reason="Tool does not exist in upstream")
4450
def test_priority_affects_call_frequency(mcp_client, echidna_campaign_running):
4551
"""
4652
Test that prioritization increases call frequency.
@@ -104,6 +110,7 @@ def test_priority_affects_call_frequency(mcp_client, echidna_campaign_running):
104110
f"Prioritized function not called more: {initial_count} -> {updated_count}"
105111

106112

113+
@pytest.mark.skip(reason="Tool does not exist in upstream")
107114
def test_priority_persistence(mcp_client):
108115
"""Test that priority persists across multiple calls."""
109116
function_sig = "balanceOf(address)"
@@ -125,6 +132,7 @@ def test_priority_persistence(mcp_client):
125132
assert result3["cleared"] is True
126133

127134

135+
@pytest.mark.skip(reason="Tool does not exist in upstream")
128136
def test_prioritize_multiple_functions(mcp_client):
129137
"""Test prioritizing multiple functions sequentially."""
130138
functions = [
@@ -140,6 +148,7 @@ def test_prioritize_multiple_functions(mcp_client):
140148
assert result["prioritized"] is True
141149

142150

151+
@pytest.mark.skip(reason="Tool does not exist in upstream")
143152
def test_clear_after_prioritize(mcp_client, echidna_campaign_running):
144153
"""Test that clearing priorities returns to uniform distribution."""
145154
# This is a basic validation - full statistical testing would need many samples
@@ -156,4 +165,3 @@ def test_clear_after_prioritize(mcp_client, echidna_campaign_running):
156165
assert result["cleared"] is True
157166

158167
# After clearing, distribution should normalize (this is qualitative)
159-
# Full validation in T054 integration test

tests/mcp/test_read_logs.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
Feature: 001-mcp-agent-commands
44
Phase 5, Task T058
55
6+
NOTE: The read_logs tool is currently commented out in upstream (lib/Echidna/MCP.hs).
7+
These tests are preserved for when the tool is re-enabled.
68
Tests for read_logs MCP tool.
79
"""
810

@@ -11,6 +13,7 @@
1113
from tests.mcp.scripts.mcp_client_wrapper import MCPClientV2
1214

1315

16+
@pytest.mark.skip(reason="read_logs tool is commented out in upstream")
1417
def test_read_logs_initial(mcp_client):
1518
"""Test that logs exist on fresh campaign."""
1619
result = mcp_client.call_tool("read_logs", {"max_count": 10})
@@ -21,6 +24,7 @@ def test_read_logs_initial(mcp_client):
2124
assert result["count"] >= 0
2225

2326

27+
@pytest.mark.skip(reason="read_logs tool is commented out in upstream")
2428
def test_read_logs_pagination(mcp_client):
2529
"""Test that pagination parameters work correctly."""
2630
# Get first batch
@@ -39,6 +43,7 @@ def test_read_logs_pagination(mcp_client):
3943
assert isinstance(result2["events"], list)
4044

4145

46+
@pytest.mark.skip(reason="read_logs tool is commented out in upstream")
4247
@pytest.mark.timeout(1) # 1 second max
4348
def test_read_logs_response_time(mcp_client):
4449
"""Test that read_logs responds within 100ms (p95 < 150ms)."""

0 commit comments

Comments
 (0)