Skip to content

Commit da5dc6e

Browse files
authored
feat(mcp): Allow to pass configuration file path via MCP tools (#1691)
1 parent ca12903 commit da5dc6e

File tree

25 files changed

+472
-275
lines changed

25 files changed

+472
-275
lines changed

.ai/mcp/mcp.json

Whitespace-only changes.

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pip install nox
4444
And multiple Python versions:
4545

4646
```commandline
47-
uv python install 3.9 3.10 3.11 3.12 3.13
47+
uv python install 3.10 3.11 3.12 3.13
4848
```
4949

5050
To run all nox sessions (defined in ``noxfile.py``), run in the root of the project:

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ The most common questions with answers can be found at the bottom ⬇ of this RE
4242

4343
## Requirements
4444

45-
Python 3.9+ :snake: and Robot Framework 4.0+ :robot:.
45+
Python 3.10+ :snake: and Robot Framework 5.0+ :robot:.
4646

4747
## Installation
4848

docs/integrations/ai.md

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ Install Robocop with MCP support:
2424
pip install robotframework-robocop[mcp]
2525
```
2626

27-
!!! note "Python Version Requirement"
28-
MCP support requires Python 3.10 or higher. The core Robocop functionality still supports Python 3.9+.
29-
3027
### Running the Server
3128

3229
#### Standalone (Testing)
@@ -139,6 +136,14 @@ If the server doesn't appear or tools don't work:
139136
4. **Check config syntax**: Ensure valid JSON (no trailing commas)
140137
5. **Path issues**: If `robocop-mcp` isn't found, use the full path (e.g., `/usr/local/bin/robocop-mcp`)
141138

139+
### Configuration
140+
141+
Robocop MCP loads its configuration in this order:
142+
143+
- from the default config file when the MCP server is started in a directory that contains it
144+
- from a config file provided via the `config_path` tool parameter
145+
- from any tool-specific override options, when available
146+
142147
### Available Tools
143148

144149
#### Linting Tools
@@ -147,15 +152,16 @@ If the server doesn't appear or tools don't work:
147152

148153
Lint Robot Framework code provided as text content.
149154

150-
| Parameter | Type | Description |
151-
|-----------|------|-------------|
152-
| `content` | string | Robot Framework source code to lint (required) |
153-
| `filename` | string | Virtual filename for file type detection (default: "stdin.robot") |
155+
| Parameter | Type | Description |
156+
|-----------|-----------|-------------|
157+
| `content` | string | Robot Framework source code to lint (required) |
158+
| `filename` | string | Virtual filename for file type detection (default: "stdin.robot") |
154159
| `select` | list[str] | Rule IDs/names to enable (e.g., `["LEN01", "too-long-keyword"]`) |
155160
| `ignore` | list[str] | Rule IDs/names to ignore |
156-
| `threshold` | string | Minimum severity: `I` (Info), `W` (Warning), or `E` (Error) |
157-
| `limit` | int | Maximum number of issues to return |
161+
| `threshold` | string | Minimum severity: `I` (Info), `W` (Warning), or `E` (Error) |
162+
| `limit` | int | Maximum number of issues to return |
158163
| `configure` | list[str] | Rule configurations (e.g., `["line-too-long.line_length=140"]`) |
164+
| `config_path` | Path | Path to the Robocop toml configuration file |
159165

160166
**Returns:** List of diagnostic issues, each containing `rule_id`, `name`, `message`, `severity`, `line`, `column`, `end_line`, `end_column`.
161167

@@ -171,6 +177,7 @@ Lint a single Robot Framework file from disk.
171177
| `threshold` | string | Minimum severity: `I`, `W`, or `E` |
172178
| `limit` | int | Maximum number of issues to return |
173179
| `configure` | list[str] | Rule configurations |
180+
| `config_path` | Path | Path to the Robocop toml configuration file |
174181

175182
**Returns:** List of diagnostic issues (same format as lint_content).
176183

@@ -190,6 +197,7 @@ Lint multiple Robot Framework files using paths or glob patterns. Useful for che
190197
| `configure` | list[str] | Rule configurations |
191198
| `group_by` | string | Group results: `"severity"`, `"rule"`, or `"file"` |
192199
| `summarize_only` | bool | Return only stats without individual issues (default: false) |
200+
| `config_path` | Path | Path to the Robocop toml configuration file |
193201

194202
**Returns:** Dictionary with `total_files`, `total_issues`, `files_with_issues`, `issues` (omitted when `summarize_only`), `summary`, `limited`, `offset`, `has_more`, `unmatched_patterns`, `group_counts` (when grouped), and `top_rules` (when `summarize_only`).
195203

@@ -202,6 +210,7 @@ Analyze Robot Framework code and get actionable fix suggestions for each issue.
202210
| `content` | string | Robot Framework source code to analyze (required) |
203211
| `filename` | string | Virtual filename (default: "stdin.robot") |
204212
| `rule_ids` | list[str] | Specific rule IDs to get suggestions for |
213+
| `config_path` | Path | Path to the Robocop toml configuration file |
205214

206215
**Returns:** Dictionary with:
207216

@@ -224,6 +233,7 @@ Format Robot Framework code and return the formatted result.
224233
| `select` | list[str] | Formatter names to apply (default: all enabled formatters) |
225234
| `space_count` | int | Spaces for indentation (default: 4) |
226235
| `line_length` | int | Maximum line length (default: 120) |
236+
| `config_path` | Path | Path to the Robocop toml configuration file |
227237

228238
**Returns:** Dictionary with `formatted` (the code), `changed` (boolean), and `diff` (unified diff if changed).
229239

@@ -245,6 +255,7 @@ Format Robot Framework code and lint the result in one operation. **Recommended
245255
| `limit` | int | Maximum issues to return |
246256
| `configure` | list[str] | Rule configurations |
247257
| `overwrite` | bool | If True and `file_path` is used, write formatted content back to file (default: false) |
258+
| `config_path` | Path | Path to the Robocop toml configuration file |
248259

249260
**Returns:** Dictionary with `formatted`, `changed`, `diff`, `issues` (remaining), `issues_before`, `issues_after`, `issues_fixed`. When `file_path` is used, also includes `file` and `written`.
250261

@@ -259,6 +270,7 @@ Format a Robot Framework file from disk. Can optionally overwrite the file with
259270
| `space_count` | int | Spaces for indentation (default: 4) |
260271
| `line_length` | int | Maximum line length (default: 120) |
261272
| `overwrite` | bool | Write formatted content back to file (default: false) |
273+
| `config_path` | Path | Path to the Robocop toml configuration file |
262274

263275
**Returns:** Dictionary with `file`, `formatted`, `changed`, `diff`, and `written` (whether file was overwritten).
264276

@@ -275,6 +287,7 @@ Format multiple Robot Framework files using paths or glob patterns. Can optional
275287
| `line_length` | int | Maximum line length (default: 120) |
276288
| `overwrite` | bool | Write formatted content back to files (default: false) |
277289
| `summarize_only` | bool | Return only stats without per-file results (default: false) |
290+
| `config_path` | Path | Path to the Robocop toml configuration file |
278291

279292
**Returns:** Dictionary with `total_files`, `files_changed`, `files_unchanged`, `files_written`, `results` (omitted when `summarize_only`), `errors`, `unmatched_patterns`.
280293

@@ -334,6 +347,7 @@ Explain a specific issue at a given line with surrounding context. More detailed
334347
| `line` | int | The line number to explain (1-indexed, required) |
335348
| `filename` | string | Virtual filename (default: "stdin.robot") |
336349
| `context_lines` | int | Number of lines to show before/after (default: 3) |
350+
| `config_path` | Path | Path to the Robocop toml configuration file |
337351

338352
**Returns:** Dictionary with:
339353

@@ -359,6 +373,7 @@ Get rich context for LLM-assisted fixing of Robot Framework code issues. This to
359373
| `line` | int | Specific line to get context for (None = all issues) |
360374
| `rule_ids` | list[str] | Filter to specific rule IDs (e.g., `["LEN01", "NAME02"]`) |
361375
| `context_lines` | int | Lines of context before and after target (default: 5) |
376+
| `config_path` | Path | Path to the Robocop toml configuration file |
362377

363378
**Returns:** Dictionary with:
364379

@@ -423,6 +438,7 @@ List all available linting rules with optional filtering.
423438
| `category` | string | Filter by category: `"LEN"`, `"NAME"`, `"DOC"`, `"SPACE"`, etc. |
424439
| `severity` | string | Filter by severity: `"I"`, `"W"`, or `"E"` |
425440
| `enabled_only` | bool | Only return enabled rules (default: false) |
441+
| `config_path` | Path | Path to the Robocop toml configuration file |
426442

427443
**Returns:** List of rule summaries with `rule_id`, `name`, `severity`, `enabled`, `message`.
428444

@@ -433,6 +449,7 @@ List all available formatters.
433449
| Parameter | Type | Description |
434450
|-----------|------|-------------|
435451
| `enabled_only` | bool | Only return enabled formatters (default: true) |
452+
| `config_path` | Path | Path to the Robocop toml configuration file |
436453

437454
**Returns:** List of formatter summaries with `name`, `enabled`, `description`.
438455

@@ -443,6 +460,7 @@ Get detailed documentation for a specific linting rule.
443460
| Parameter | Type | Description |
444461
|-----------|------|-------------|
445462
| `rule_name_or_id` | string | Rule name (e.g., `"too-long-keyword"`) or ID (e.g., `"LEN01"`) (required) |
463+
| `config_path` | Path | Path to the Robocop toml configuration file |
446464

447465
**Returns:** Dictionary with `rule_id`, `name`, `message`, `severity`, `enabled`, `deprecated`, `docs`, `parameters`, `added_in_version`, `version_requirement`.
448466

@@ -453,6 +471,7 @@ Get detailed documentation for a specific formatter.
453471
| Parameter | Type | Description |
454472
|-----------|------|-------------|
455473
| `formatter_name` | string | Formatter name (e.g., `"NormalizeSeparators"`) (required) |
474+
| `config_path` | Path | Path to the Robocop toml configuration file |
456475

457476
**Returns:** Dictionary with `name`, `enabled`, `docs`, `min_version`, `parameters`, `skip_options`.
458477

@@ -467,6 +486,7 @@ Search for linting rules by keyword. Searches across rule names, messages, and d
467486
| `category` | string | Filter by category: `"LEN"`, `"NAME"`, `"DOC"`, etc. |
468487
| `severity` | string | Filter by severity: `"I"`, `"W"`, or `"E"` |
469488
| `limit` | int | Maximum results to return (default: 20) |
489+
| `config_path` | Path | Path to the Robocop toml configuration file |
470490

471491
**Returns:** List of matching rules with `rule_id`, `name`, `message`, `severity`, `enabled`, `match_field`, `match_snippet`.
472492

docs/user_guide/intro.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Requirements
44

5-
Python 3.9+ and Robot Framework 4+.
5+
Python 3.10+ and Robot Framework 5+.
66

77
## Installation
88

noxfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
nox.options.default_venv_backend = "uv"
1212

13-
PYTHON_VERSIONS = ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
13+
PYTHON_VERSIONS = ["3.10", "3.11", "3.12", "3.13", "3.14"]
1414

1515
ROBOT_VERSIONS = ["robotframework==4.*", "robotframework==5.*", "robotframework==6.*", "robotframework==7.*"]
1616
ROBOCOP_VERSIONS = (

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ robocop-mcp = "robocop.mcp.server:main"
5151

5252
[project.optional-dependencies]
5353
mcp = [
54-
"fastmcp>=2.13.0"
54+
"fastmcp>=2.13.0,<3"
5555
]
5656

5757
[project.urls]

src/robocop/mcp/cache.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
from typing import TYPE_CHECKING
77

88
if TYPE_CHECKING:
9+
from pathlib import Path
10+
911
from robocop.runtime.resolved_config import ResolvedConfig
1012

1113

12-
@lru_cache(maxsize=1)
13-
def get_linter_config() -> ResolvedConfig:
14+
@lru_cache
15+
def get_linter_config(config_path: Path | None) -> ResolvedConfig:
1416
"""
1517
Get cached LinterConfig with all rules loaded.
1618
@@ -24,14 +26,14 @@ def get_linter_config() -> ResolvedConfig:
2426
from robocop.config.manager import ConfigManager
2527
from robocop.runtime.resolver import ConfigResolver
2628

27-
manager = ConfigManager()
29+
manager = ConfigManager(config=config_path)
2830
resolver = ConfigResolver(load_rules=True)
2931

3032
return resolver.resolve_config(manager.default_config)
3133

3234

33-
@lru_cache(maxsize=1)
34-
def get_formatter_config() -> ResolvedConfig:
35+
@lru_cache
36+
def get_formatter_config(config_path: Path | None) -> ResolvedConfig:
3537
"""
3638
Get cached FormatterConfig with all formatters loaded.
3739
@@ -45,7 +47,7 @@ def get_formatter_config() -> ResolvedConfig:
4547
from robocop.config.manager import ConfigManager
4648
from robocop.runtime.resolver import ConfigResolver
4749

48-
manager = ConfigManager()
50+
manager = ConfigManager(config=config_path)
4951
resolver = ConfigResolver(load_formatters=True)
5052

5153
return resolver.resolve_config(manager.default_config)

src/robocop/mcp/resources.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,23 @@
1010
from robocop.mcp.cache import get_formatter_config, get_linter_config
1111

1212
if TYPE_CHECKING:
13+
from pathlib import Path
14+
1315
from fastmcp import FastMCP
1416

1517

16-
def _get_rules_catalog() -> list[dict[str, Any]]:
18+
def _get_rules_catalog(config_path: Path | None = None) -> list[dict[str, Any]]:
1719
"""
1820
Get catalog of all available linting rules.
1921
22+
Args:
23+
config_path: Path to the Robocop toml configuration file
24+
2025
Returns:
2126
list[dict[str, Any]]: List of rules with basic information.
2227
2328
"""
24-
linter_config = get_linter_config()
29+
linter_config = get_linter_config(config_path)
2530

2631
# Use a set to deduplicate (rules dict has both id and name pointing to same rule)
2732
seen_ids: set[str] = set()
@@ -47,15 +52,18 @@ def _get_rules_catalog() -> list[dict[str, Any]]:
4752
return sorted(rules, key=operator.itemgetter("rule_id"))
4853

4954

50-
def _get_formatters_catalog() -> list[dict[str, Any]]:
55+
def _get_formatters_catalog(config_path: Path | None = None) -> list[dict[str, Any]]:
5156
"""
5257
Get catalog of all available formatters.
5358
59+
Args:
60+
config_path: Path to the Robocop toml configuration file
61+
5462
Returns:
5563
list[dict[str, Any]]: List of formatters with basic information.
5664
5765
"""
58-
formatter_config = get_formatter_config()
66+
formatter_config = get_formatter_config(config_path)
5967

6068
formatters = []
6169
for name, formatter in formatter_config.formatters.items():
@@ -73,19 +81,20 @@ def _get_formatters_catalog() -> list[dict[str, Any]]:
7381
return sorted(formatters, key=operator.itemgetter("name"))
7482

7583

76-
def _get_rule_details(rule_id: str) -> dict[str, Any]:
84+
def _get_rule_details(rule_id: str, config_path: Path | None = None) -> dict[str, Any]:
7785
"""
7886
Get detailed information about a specific rule.
7987
8088
Args:
8189
rule_id: Rule ID (e.g., "LEN01") or name (e.g., "too-long-keyword")
90+
config_path: Path to the Robocop toml configuration file
8291
8392
Returns:
8493
dict[str, Any]: Detailed rule information including full documentation
8594
and configurable parameters.
8695
8796
"""
88-
linter_config = get_linter_config()
97+
linter_config = get_linter_config(config_path)
8998

9099
if rule_id not in linter_config.rules:
91100
raise ResourceError(f"Rule '{rule_id}' not found")
@@ -123,7 +132,7 @@ def _get_rule_details(rule_id: str) -> dict[str, Any]:
123132
def register_resources(mcp: FastMCP) -> None:
124133
"""Register all MCP resources with the server."""
125134

126-
@mcp.resource("robocop://rules")
135+
@mcp.resource("robocop://rules") # FIXME: add config handling
127136
def get_rules_catalog() -> list[dict[str, Any]]:
128137
"""
129138
Get catalog of all available linting rules.

0 commit comments

Comments
 (0)