|
| 1 | +# Code Review - 2026-04-13 |
| 2 | + |
| 3 | +**Commits Reviewed**: dad40f58d835b3e34e49d43ee0bb75285a9f5d10 |
| 4 | +**Branch:** agent-tasks/482 → main |
| 5 | +**Type:** feat |
| 6 | + |
| 7 | +## Summary |
| 8 | + |
| 9 | +This PR adds declarative MCP server configuration support, allowing users to define multiple MCP servers in JSON config files (compatible with Claude Desktop/Cursor format) and load them automatically via `load_mcp_clients_from_config()`. It also extends `config_to_agent()` to accept an `mcp_servers` field. Supports stdio, SSE, and streamable-HTTP transports with JSON schema validation, tool filters (regex), and auto-detection of transport type. |
| 10 | + |
| 11 | +## Recommendation |
| 12 | + |
| 13 | +**Decision:** Request Changes |
| 14 | + |
| 15 | +**Rationale:** The feature design is sound and addresses a real user need. The code is well-structured with good separation of concerns and thorough test coverage. However, there are several outstanding issues from the prior automated review that remain unaddressed, plus a few additional concerns around test placement, export paths, and module-level I/O patterns. |
| 16 | + |
| 17 | +## Quick Stats |
| 18 | + |
| 19 | +- Files Changed: 7 |
| 20 | +- Lines Added: 957 |
| 21 | +- Lines Removed: 28 |
| 22 | +- Test Coverage: yes (unit + integration, 94.69% patch coverage per Codecov) |
| 23 | +- Breaking Changes: no |
| 24 | + |
| 25 | +## Critical Issues |
| 26 | + |
| 27 | +No critical issues (security, data loss, breaking changes). |
| 28 | + |
| 29 | +## Important Issues |
| 30 | + |
| 31 | +### Issue 1: Test file placed in wrong directory |
| 32 | +- **File:** `tests/strands/tools/mcp/test_mcp_config.py` |
| 33 | +- **Problem:** The unit tests for `strands.experimental.mcp_config` are located at `tests/strands/tools/mcp/test_mcp_config.py`. Per AGENTS.md, tests should mirror the `src/` directory structure. The module lives in `src/strands/experimental/mcp_config.py`, so the tests should be in `tests/strands/experimental/`. |
| 34 | +- **Suggestion:** Move to `tests/strands/experimental/test_mcp_config.py`. |
| 35 | + |
| 36 | +### Issue 2: `load_mcp_clients_from_config` not exported from `strands.experimental` |
| 37 | +- **File:** `src/strands/experimental/__init__.py` |
| 38 | +- **Problem:** The new public function `load_mcp_clients_from_config` is not added to `strands.experimental.__init__.py`'s `__all__` or imports. Users must import from the internal module path `strands.experimental.mcp_config`, which is not a stable public API surface. The PR description also still shows the old import path `from strands.tools.mcp import load_mcp_clients_from_config`. |
| 39 | +- **Suggestion:** Add to `__init__.py`: |
| 40 | +```python |
| 41 | +from .mcp_config import load_mcp_clients_from_config |
| 42 | + |
| 43 | +__all__ = ["config_to_agent", "load_mcp_clients_from_config", "tools", "steering"] |
| 44 | +``` |
| 45 | + |
| 46 | +### Issue 3: Module-level file I/O at import time |
| 47 | +- **File:** `src/strands/experimental/mcp_config.py:30-32`, `src/strands/experimental/agent_config.py:25-27` |
| 48 | +- **Problem:** Both modules read JSON schema files at import time using `Path(__file__).parent`. This is a new pattern in this codebase (the original `agent_config.py` had the schema inline as a Python dict). It introduces file I/O side effects on import and may not work correctly in zipped/packaged distributions. |
| 49 | +- **Suggestion:** Either: |
| 50 | + 1. Keep schemas as inline Python dicts (consistent with original pattern, zero I/O) |
| 51 | + 2. Use `importlib.resources` for reading package data files (recommended for packaged distributions) |
| 52 | + 3. Lazy-load via `functools.lru_cache` on a loader function |
| 53 | + |
| 54 | +### Issue 4: `$ref` in JSON schema manually resolved in Python |
| 55 | +- **File:** `src/strands/experimental/agent_config.py:31`, `src/strands/experimental/agent_config.schema.json:31` |
| 56 | +- **Problem:** The `agent_config.schema.json` contains `"$ref": "mcp_server_config.schema.json"` which is then manually replaced in Python code: `AGENT_CONFIG_SCHEMA["properties"]["mcp_servers"]["additionalProperties"] = MCP_SERVER_CONFIG_SCHEMA`. This makes the JSON file misleading when read standalone — any IDE or JSON Schema tooling would fail to resolve the `$ref`. |
| 57 | +- **Suggestion:** Either inline the MCP server schema directly in `agent_config.schema.json`, or use `jsonschema.RefResolver` to properly resolve `$ref`s. If keeping separate files, add a comment explaining the programmatic resolution. |
| 58 | + |
| 59 | +### Issue 5: Docstring unclear about `re.match` prefix-match semantics |
| 60 | +- **File:** `src/strands/experimental/mcp_config.py:40-42` |
| 61 | +- **Problem:** The docstring says `Exact-match strings like "^echo$" work correctly as regex since they match themselves.` But the actual matching in `mcp_client.py:989` uses `pattern.match()` (prefix match, not full match). So `"echo"` in a filter will match `"echo_extra"` too. Users writing `"echo"` in their JSON config likely expect exact matching. |
| 62 | +- **Suggestion:** Update the docstring to clearly document this behavior: |
| 63 | +``` |
| 64 | +All filter strings are compiled as regex patterns and matched using ``re.match`` |
| 65 | +(prefix match from start of string). Use ``"^echo$"`` for exact matching. |
| 66 | +``"echo"`` will match any tool name starting with "echo". |
| 67 | +``` |
| 68 | + |
| 69 | +## Suggestions |
| 70 | + |
| 71 | +- The PR description still references the old import path `from strands.tools.mcp import load_mcp_clients_from_config`. Should be updated to reflect the actual location. |
| 72 | +- Consider whether `MCP_SERVER_CONFIG_SCHEMA` needs to be a public module-level export from `mcp_config.py`. If it's only used internally by `agent_config.py`, prefix it with `_`. |
| 73 | +- The integration tests at `tests_integ/mcp/test_mcp_config.py` are well-placed and thorough. |
| 74 | + |
| 75 | +## Positive Highlights |
| 76 | + |
| 77 | +- Clean separation between `mcp_config.py` (MCP-specific) and `agent_config.py` (agent-level integration) |
| 78 | +- All prior review feedback (regex heuristic, private naming, lambda→def, mcpServers wrapper, empty dict simplification) was addressed thoughtfully in the force-push |
| 79 | +- Comprehensive test coverage: unit tests for schema validation, tool filter parsing, transport creation, file loading; integration tests with actual echo server |
| 80 | +- Good error messages that include server names and JSON schema paths for debugging |
| 81 | +- Transport auto-detection from config fields is intuitive and matches user expectations |
| 82 | +- JSON schema validation catches config errors early with clear messages |
| 83 | + |
| 84 | +## Files Reviewed |
| 85 | + |
| 86 | +| File | Status | Notes | |
| 87 | +|------|--------|-------| |
| 88 | +| `src/strands/experimental/agent_config.py` | Modified | Added mcp_servers handling, moved schema to JSON file | |
| 89 | +| `src/strands/experimental/agent_config.schema.json` | Added | Agent config JSON schema (extracted from Python dict) | |
| 90 | +| `src/strands/experimental/mcp_config.py` | Added | Core MCP config parsing and MCPClient factory | |
| 91 | +| `src/strands/experimental/mcp_server_config.schema.json` | Added | MCP server config JSON schema | |
| 92 | +| `tests/strands/experimental/test_agent_config.py` | Modified | Added mcp_servers integration tests | |
| 93 | +| `tests/strands/tools/mcp/test_mcp_config.py` | Added | Unit tests (wrong directory - should be experimental/) | |
| 94 | +| `tests_integ/mcp/test_mcp_config.py` | Added | Integration tests with echo server | |
| 95 | + |
| 96 | +## Checklist |
| 97 | + |
| 98 | +- [x] Type annotations complete |
| 99 | +- [ ] Documentation present (not exported from `__init__.py`, PR description outdated) |
| 100 | +- [x] Tests included (comprehensive unit + integration) |
| 101 | +- [x] No breaking changes |
| 102 | +- [ ] Follows project patterns (test file placement, module-level I/O) |
| 103 | +- [x] Error handling appropriate |
| 104 | + |
| 105 | +## Additional Notes |
| 106 | + |
| 107 | +- This is the second iteration of the PR. The first round of automated review identified 7 issues, all of which were addressed in the force-push to `dad40f5`. The second round identified 6 more issues, which are the basis for this review. |
| 108 | +- The `mcpServers` (camelCase) wrapper key in `load_mcp_clients_from_config` vs `mcp_servers` (snake_case) in agent config is a good design choice — it maintains Python conventions in the agent config while supporting the Claude Desktop/Cursor JSON convention in the standalone loader. |
| 109 | +- Codecov reports 94.69% patch coverage with 6 lines missing coverage, primarily in `mcp_config.py` (3 missing + 1 partial) and `agent_config.py` (1 missing + 1 partial). |
0 commit comments