Skip to content

LCORE-1834: MCP Approval Configuration#1773

Merged
tisnik merged 1 commit into
lightspeed-core:mainfrom
asimurka:hitl_config
May 20, 2026
Merged

LCORE-1834: MCP Approval Configuration#1773
tisnik merged 1 commit into
lightspeed-core:mainfrom
asimurka:hitl_config

Conversation

@asimurka
Copy link
Copy Markdown
Contributor

@asimurka asimurka commented May 20, 2026

Description

Adds configuration blocks for MCP server approval policy.

Type of change

  • Refactor
  • New feature
  • Bug fix
  • CVE fix
  • Optimization
  • Documentation Update
  • Configuration Update
  • Bump-up service version
  • Bump-up dependent library
  • Bump-up library or tool used for development (does not change the final image)
  • CI configuration change
  • Konflux configuration change
  • Unit tests improvement
  • Integration tests improvement
  • End to end tests improvement
  • Benchmarks improvement

Tools used to create PR

Identify any AI code assistants used in this PR (for transparency and review context)

  • Assisted-by: Cursor

Related Tickets & Documents

Checklist before requesting a review

  • I have performed a self-review of my code.
  • PR has passed all pre-merge test jobs.
  • If it is a core feature, I have added thorough tests.

Testing

  • Please provide detailed steps to perform tests related to this code change.
  • How were the fix/results from this change verified? Please provide relevant screenshots or results.

Summary by CodeRabbit

  • New Features

    • Introduced human-in-the-loop approval system for MCP tool invocations with customizable approval timeouts and retention settings.
    • Added granular approval control enabling per-tool rules to specify which tools always require approval or never require approval.
  • Documentation

    • Updated configuration documentation with new approval system settings and schema.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

Walkthrough

This PR adds human-in-the-loop approval configuration for MCP tool invocations. New ApprovalFilter and ApprovalsConfiguration models enable per-tool and global approval control with timeout and retention settings. The approval configuration is integrated into ModelContextProtocolServer and global Configuration, exposed via AppConfig, documented in docs/config.md, and defined in OpenAPI schema. Comprehensive tests validate model constraints and JSON serialization.

Changes

Approval Configuration Implementation

Layer / File(s) Summary
Core approval models and contracts
src/models/config.py, docs/config.md, tests/unit/models/config/README.md
ApprovalFilter and ApprovalsConfiguration Pydantic models define per-tool and global approval settings. ApprovalFilter validates that no tool name appears in both always and never lists. ModelContextProtocolServer accepts require_approval as a string literal (always/never) or ApprovalFilter object. Global Configuration adds approvals field. Schema documented in config.md with examples.
Configuration access API
src/configuration.py
New AppConfig.approvals_configuration property exposes loaded Configuration.approvals to the application.
OpenAPI schema definition
docs/openapi.json
OpenAPI schemas define ApprovalFilter-Input (for input validation) and ApprovalFilter-Output (for response serialization), ApprovalsConfiguration with timeout/retention fields, and require_approval field accepting either literal string or filter object with "never" as default.
Approval configuration model validation tests
tests/unit/models/config/test_approvals_configuration.py
Tests ApprovalsConfiguration default and custom timeout/retention values, rejection of non-positive durations, ApprovalFilter defaults to empty lists, and rejection of overlapping tool names across always and never. Verifies root Configuration has approvals field with correct defaults.
MCP server integration and serialization tests
tests/unit/models/config/test_model_context_protocol_server.py, tests/unit/models/config/test_dump_configuration.py
Tests ModelContextProtocolServer.require_approval field accepts "always" literal and ApprovalFilter instances, rejects invalid literals. Updates serialization tests across multiple configuration scenarios to include approvals section and refactors MCP server defaults into shared constants.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'LCORE-1834: MCP Approval Configuration' is specific and directly reflects the main change—adding MCP approval configuration support throughout the codebase.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

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.

@asimurka asimurka requested a review from jrobertboos May 20, 2026 07:32
Copy link
Copy Markdown
Contributor

@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.

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
docs/openapi.json (1)

11403-11483: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Regenerate the OpenAPI snapshot before merge.

CI already shows docs/openapi.json differs from the generated schema, so this checked-in contract is stale. Please re-run uv run scripts/generate_openapi_schema.py docs/openapi.json and commit the regenerated output instead of hand-editing these sections.

Also applies to: 12065-12068, 14318-14334, 15340-15340

🤖 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 `@docs/openapi.json` around lines 11403 - 11483, The checked-in OpenAPI
snapshot is stale: regenerate the schema using the repository's OpenAPI
generation script (generate_openapi_schema.py) and commit the updated
docs/openapi.json so the "ApprovalFilter-Input", "ApprovalFilter-Output",
"ApprovalsConfiguration" (and other affected schema sections) match the
generated output; run the generator, review the diff, and replace the manual
edits with the generated file before merging.
🤖 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.

Inline comments:
In `@tests/unit/models/config/README.md`:
- Around line 9-10: Add a single blank line immediately after the heading "##
[test_approvals_configuration.py](test_approvals_configuration.py)" in the
README so there is an empty line between the heading and the following
paragraph, satisfying markdownlint MD022 (blanks-around-headings).

---

Outside diff comments:
In `@docs/openapi.json`:
- Around line 11403-11483: The checked-in OpenAPI snapshot is stale: regenerate
the schema using the repository's OpenAPI generation script
(generate_openapi_schema.py) and commit the updated docs/openapi.json so the
"ApprovalFilter-Input", "ApprovalFilter-Output", "ApprovalsConfiguration" (and
other affected schema sections) match the generated output; run the generator,
review the diff, and replace the manual edits with the generated file before
merging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 21bf3f5c-2ac0-4c07-a974-2d921bcb3580

📥 Commits

Reviewing files that changed from the base of the PR and between 9b2e821 and 333251f.

📒 Files selected for processing (8)
  • docs/config.md
  • docs/openapi.json
  • src/configuration.py
  • src/models/config.py
  • tests/unit/models/config/README.md
  • tests/unit/models/config/test_approvals_configuration.py
  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/models/config/test_model_context_protocol_server.py
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: build-pr
  • GitHub Check: unit_tests (3.13)
  • GitHub Check: Konflux kflux-prd-rh02 / lightspeed-stack-on-pull-request
  • GitHub Check: E2E Tests for Lightspeed Evaluation job
  • GitHub Check: E2E: server mode / ci / group 3
  • GitHub Check: E2E: library mode / ci / group 2
  • GitHub Check: E2E: library mode / ci / group 1
  • GitHub Check: E2E: library mode / ci / group 3
  • GitHub Check: E2E: server mode / ci / group 2
  • GitHub Check: E2E: server mode / ci / group 1
🧰 Additional context used
📓 Path-based instructions (4)
src/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.py: Use absolute imports for internal modules: from authentication import get_auth_dependency
Llama Stack imports: Use from llama_stack_client import AsyncLlamaStackClient
Check constants.py for shared constants before defining new ones
All modules must start with descriptive docstrings explaining purpose
Use logger = get_logger(__name__) from log.py for module logging
All functions must have complete type annotations for parameters and return types, use modern syntax (str | int), and include descriptive docstrings
Use snake_case with descriptive, action-oriented names for functions (get_, validate_, check_)
Avoid in-place parameter modification anti-patterns; return new data structures instead of modifying function parameters
Use async def for I/O operations and external API calls
Use standard log levels with clear purposes: debug() for diagnostic info, info() for program execution, warning() for unexpected events, error() for serious problems
All classes must have descriptive docstrings explaining purpose and use PascalCase with standard suffixes: Configuration, Error/Exception, Resolver, Interface
Abstract classes must use ABC with @abstractmethod decorators
Follow Google Python docstring conventions with required sections: Parameters, Returns, Raises, and Attributes for classes

Files:

  • src/configuration.py
  • src/models/config.py
src/**/configuration.py

📄 CodeRabbit inference engine (AGENTS.md)

src/**/configuration.py: All config models must extend ConfigurationBase with extra="forbid" to reject unknown fields
Use @field_validator and @model_validator for custom validation in Pydantic models

Files:

  • src/configuration.py
tests/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.py: Use pytest for all unit and integration tests; do not use unittest
Use pytest.mark.asyncio marker for async tests

Files:

  • tests/unit/models/config/test_dump_configuration.py
  • tests/unit/models/config/test_model_context_protocol_server.py
  • tests/unit/models/config/test_approvals_configuration.py
src/models/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Pydantic models must use @model_validator and @field_validator for validation and complete type annotations for all attributes, avoiding Any type

Files:

  • src/models/config.py
🧠 Learnings (2)
📚 Learning: 2026-01-12T10:58:40.230Z
Learnt from: blublinsky
Repo: lightspeed-core/lightspeed-stack PR: 972
File: src/models/config.py:459-513
Timestamp: 2026-01-12T10:58:40.230Z
Learning: In lightspeed-core/lightspeed-stack, for Python files under src/models, when a user claims a fix is done but the issue persists, verify the current code state before accepting the fix. Steps: review the diff, fetch the latest changes, run relevant tests, reproduce the issue, search the codebase for lingering references to the original problem, confirm the fix is applied and not undone by subsequent commits, and validate with local checks to ensure the issue is resolved.

Applied to files:

  • src/models/config.py
📚 Learning: 2026-02-25T07:46:33.545Z
Learnt from: asimurka
Repo: lightspeed-core/lightspeed-stack PR: 1211
File: src/models/responses.py:8-16
Timestamp: 2026-02-25T07:46:33.545Z
Learning: In the Python codebase, requests.py should use OpenAIResponseInputTool as Tool while responses.py uses OpenAIResponseTool as Tool. This difference is intentional due to differing schemas for input vs output tools in llama-stack-api. Apply this distinction consistently to other models under src/models (e.g., ensure request-related tools use the InputTool variant and response-related tools use the ResponseTool variant). If adding new tools, choose the corresponding InputTool or Tool class based on whether the tool represents input or output, and document the rationale in code comments.

Applied to files:

  • src/models/config.py
🪛 GitHub Actions: OpenAPI (Spectral) / 0_spectral.txt
docs/openapi.json

[error] 1-1: CI check failed: docs/openapi.json is out of date compared to the generated schema. Diff detected between docs/openapi.json and /tmp/openapi-generated.json. Regenerate with: uv run scripts/generate_openapi_schema.py docs/openapi.json

🪛 GitHub Actions: OpenAPI (Spectral) / spectral
docs/openapi.json

[error] 1-1: OpenAPI schema is out of date. 'diff -u docs/openapi.json /tmp/openapi-generated.json' failed, so CI reports: docs/openapi.json is out of date. Regenerate with: 'uv run scripts/generate_openapi_schema.py docs/openapi.json'.

🪛 markdownlint-cli2 (0.22.1)
tests/unit/models/config/README.md

[warning] 9-9: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)

🔇 Additional comments (6)
tests/unit/models/config/test_approvals_configuration.py (1)

1-122: LGTM!

tests/unit/models/config/test_model_context_protocol_server.py (1)

11-11: LGTM!

Also applies to: 29-30, 32-67

tests/unit/models/config/test_dump_configuration.py (1)

8-8: LGTM!

Also applies to: 29-40, 215-215, 300-300, 358-358, 364-364, 370-370, 564-564, 812-812, 1040-1040, 1258-1258

src/models/config.py (1)

470-527: LGTM!

Also applies to: 617-625, 2123-2127

docs/config.md (1)

65-97: LGTM!

Also applies to: 242-242, 457-457

src/configuration.py (1)

17-17: LGTM!

Also applies to: 463-476

Comment thread tests/unit/models/config/README.md
Comment thread docs/openapi.json
"description": "Filter configuration for restricting which MCP tools can be used.\n\n:param tool_names: (Optional) List of specific tool names that are allowed"
},
"ApprovalFilter": {
"ApprovalFilter-Input": {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This rename is caused by name conflict between our configuration model and Llama Stack's model that is part of InputToolMCP model.

Copy link
Copy Markdown
Contributor

@jrobertboos jrobertboos left a comment

Choose a reason for hiding this comment

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

LGTM, It would maybe be nice to have an example config file that shows how to make use of the approvals tho in the examples dir.

Copy link
Copy Markdown
Contributor

@tisnik tisnik left a comment

Choose a reason for hiding this comment

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

LGTM

@tisnik tisnik merged commit 4dddbde into lightspeed-core:main May 20, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants