Skip to content

Commit f88a815

Browse files
authored
refactor(mcp): use Pydantic models for structured tool outputs and add AI-powered auto-fix generation (#1603)
* refactor(mcp): use Pydantic models for structured tool outputs Replace dict-based return values with Pydantic models across all MCP tools to enable structured output with automatic JSON schema generation and type validation. Changes: - Add models.py with Pydantic models for all tool return types (DiagnosticResult, FormatContentResult, LintAndFormatResult, etc.) - Update all tool implementations to return Pydantic models instead of dicts - Fix SeveritySummary field name from 'I' to 'INFO' with alias for backward compatibility (resolves ruff E741 ambiguous variable name) Bug fixes discovered during integration testing: - Fix dict-style access (result["key"]) to attribute access (result.key) in registration.py context messages - Pydantic models use attributes - Remove 'from __future__ import annotations' from registration.py as it breaks Pydantic's runtime type evaluation for Annotated fields Testing: - Update existing unit tests for new Pydantic model structure * feat(mcp): add LLM-assisted auto-fix tools for Robot Framework issues Add two new MCP tools that enable AI-powered fixing of linting issues: - get_fix_context: Provides rich context for LLM fix generation including the problematic code snippet, issue details with fix_suggestion and rule_docs, and structured guidance for generating fixes - apply_fix: Applies line-based replacements and validates fixes by re-linting. Detects if a fix made things worse and supports both preview mode and file overwriting New Pydantic models: - CodeSnippet, IssueForFix, GetFixContextResult - FixReplacement, ApplyFixResult This enables the workflow: get_fix_context → LLM generates fix → apply_fix with validation, supporting use cases like fixing naming conventions, adding missing documentation, and restructuring code. * fix: update docs and remove duplicate line * fix: replace lambda with attrgetter and replace list comprehension with a simpler approach
1 parent d88f9bf commit f88a815

File tree

14 files changed

+2524
-1379
lines changed

14 files changed

+2524
-1379
lines changed

docs/integrations/ai.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,75 @@ Explain a specific issue at a given line with surrounding context. More detailed
343343
- `related_issues`: Issues on nearby lines (within 2 lines)
344344
- `context`: Surrounding code with line numbers
345345

346+
#### LLM-Assisted Fixing Tools
347+
348+
These tools enable AI assistants to generate and apply intelligent fixes for Robot Framework code issues.
349+
350+
##### get_fix_context
351+
352+
Get rich context for LLM-assisted fixing of Robot Framework code issues. This tool provides everything an AI needs to generate a proper fix: the problematic code snippet, detailed issue information, rule documentation, and structured guidance.
353+
354+
| Parameter | Type | Description |
355+
|-----------|------|-------------|
356+
| `content` | string | Robot Framework source code (use this OR `file_path`) |
357+
| `file_path` | string | Absolute path to .robot or .resource file (use this OR `content`) |
358+
| `filename` | string | Virtual filename when using content (default: "stdin.robot") |
359+
| `line` | int | Specific line to get context for (None = all issues) |
360+
| `rule_ids` | list[str] | Filter to specific rule IDs (e.g., `["LEN01", "NAME02"]`) |
361+
| `context_lines` | int | Lines of context before and after target (default: 5) |
362+
363+
**Returns:** Dictionary with:
364+
365+
- `file_path`: File path if from file
366+
- `full_content`: The complete file/content being analyzed
367+
- `target_snippet`: The problematic code section with `content`, `start_line`, `end_line`
368+
- `issues`: List of issues with `rule_id`, `name`, `message`, `severity`, `line`, `column`, `fix_suggestion`, `rule_docs`
369+
- `llm_guidance`: Structured guidance for the LLM on how to generate the fix
370+
371+
##### apply_fix
372+
373+
Apply an LLM-generated fix to Robot Framework code. Takes a line-based replacement and applies it to the code, then validates the fix by re-linting to ensure issues were actually resolved.
374+
375+
| Parameter | Type | Description |
376+
|-----------|------|-------------|
377+
| `content` | string | Original Robot Framework source (use this OR `file_path`) |
378+
| `file_path` | string | Path to the file to fix (use this OR `content`) |
379+
| `filename` | string | Virtual filename when using content (default: "stdin.robot") |
380+
| `replacement` | object | The line-based replacement with `start_line`, `end_line`, `new_content` (required) |
381+
| `overwrite` | bool | Write the fix to disk - only with `file_path` (default: false) |
382+
| `validate` | bool | Re-lint to validate the fix resolved issues (default: true) |
383+
| `select` | list[str] | Rule IDs to check in validation |
384+
| `ignore` | list[str] | Rule IDs to ignore in validation |
385+
386+
**Returns:** Dictionary with:
387+
388+
- `success`: Whether the fix was successfully applied and validated
389+
- `file_path`: File path if written to disk
390+
- `written`: Whether the fix was written to disk
391+
- `new_content`: The content after applying the fix
392+
- `diff`: Unified diff showing the changes
393+
- `issues_before`: Number of issues before the fix
394+
- `issues_after`: Number of issues after the fix
395+
- `issues_fixed`: Number of issues resolved by the fix
396+
- `remaining_issues`: Issues that remain after the fix (limited to first 10)
397+
- `validation_error`: Error message if fix validation failed
398+
399+
**Example workflow:**
400+
401+
```python
402+
# 1. Get context for an issue at line 42
403+
context = get_fix_context(file_path="/path/to/test.robot", line=42)
404+
405+
# 2. AI uses context.llm_guidance and context.issues to generate a fix
406+
407+
# 3. Apply the fix
408+
apply_fix(
409+
file_path="/path/to/test.robot",
410+
replacement={"start_line": 42, "end_line": 43, "new_content": " Log Fixed code"},
411+
overwrite=True
412+
)
413+
```
414+
346415
#### Discovery Tools
347416

348417
##### list_rules
@@ -567,6 +636,15 @@ Once the MCP server is configured, you can use natural language to interact with
567636
>
568637
> "What issues in this code can be auto-fixed vs need manual changes?"
569638
639+
#### LLM-Assisted Fixing
640+
641+
**Get context and apply AI-generated fixes:**
642+
> "Get the context for the issue at line 42 in my test file so you can fix it"
643+
>
644+
> "Fix the naming issue at line 15 - get the context first, then generate and apply the fix"
645+
>
646+
> "Help me fix all the issues in this file one by one"
647+
570648
#### Configuring Rules
571649
572650
**Custom thresholds:**

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,14 @@ extend-exclude = [
186186
"PERF401", # list comprehension vs for loop is style choice
187187
"TRY300", # return in try block is fine here
188188
"C401", # set comprehension vs generator is style choice
189+
"TC001", # Pydantic models need runtime import for schema generation
189190
"TC002", # Context must be runtime import for FastMCP dependency injection
190191
"D417", # ctx param is injected by FastMCP, not user-facing
191192
"PLR0915", # register_tools has many statements by design
192193
]
194+
"src/robocop/mcp/tools/registration.py" = [
195+
"FA102", # can't use future annotations - breaks Pydantic runtime evaluation
196+
]
193197
# temporary because of the rules description
194198
"src/robocop/linter/rules/*" = ["D205"]
195199
# bug in typer where | None can't be used

0 commit comments

Comments
 (0)