Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dependencies = [
"mcp>=1.23.3",
"strands-agents>=1.19.0",
"compliance-trestle>=3.12.0",
"regex>=2024.0.0",
]
requires-python = ">=3.11"
description = "AI agent tools for Open Security Controls Assessment Language (OSCAL)."
Expand Down
7 changes: 7 additions & 0 deletions src/mcp_server_for_oscal/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ def _setup_tools() -> None:
list_components,
query_component_definition,
)
from mcp_server_for_oscal.tools.query_documentation import query_oscal_documentation
from mcp_server_for_oscal.tools.validate_oscal_content import (
validate_oscal_content,
validate_oscal_file,
)

# Register tools with MCP server
# don't register the query_oscal_documentation tool unless we have a KB ID
Expand All @@ -61,6 +66,8 @@ def _setup_tools() -> None:
mcp.add_tool(list_components)
mcp.add_tool(list_capabilities)
mcp.add_tool(get_capability)
mcp.add_tool(validate_oscal_content)
mcp.add_tool(validate_oscal_file)

@mcp.tool(name="about", description="Get metadata about the server itself")
def about() -> dict:
Expand Down
40 changes: 36 additions & 4 deletions src/mcp_server_for_oscal/tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This package contains all tool implementations for the OSCAL MCP server. Each to

## Available Tools

### 1. List OSCAL Models
### 1. List OSCAL Models
**Tool**: `list_oscal_models`

Returns metadata about all available OSCAL model types including:
Expand Down Expand Up @@ -120,7 +120,7 @@ Queries authoritative OSCAL documentation using Amazon Bedrock Knowledge Base. U

**Returns**: Results from knowledge base as Bedrock RetrieveResponseTypeDef object

**Requirements**:
**Requirements**:
- Requires `OSCAL_KB_ID` environment variable to be set
- Requires AWS credentials configured (via profile or environment)
- Optional: Set `OSCAL_AWS_PROFILE` to use specific AWS profile
Expand All @@ -129,7 +129,36 @@ Queries authoritative OSCAL documentation using Amazon Bedrock Knowledge Base. U

---

### 8. About
### 8. Validate OSCAL Content
**Tool**: `validate_oscal_content`

Validates OSCAL JSON content through a multi-level pipeline:

| Level | What it checks | Implementation |
|-------|---------------|----------------|
| 1. Well-formedness | Valid JSON, is a dict | `json.loads()` |
| 2. JSON Schema | Conforms to NIST OSCAL schema | `jsonschema.Draft7Validator` with bundled schemas |
| 3. Trestle | Semantic checks via Pydantic models | `trestle.oscal.*` model instantiation |
| 4. oscal-cli | Full NIST validation | `subprocess.run()` if on PATH |

**Parameters**:
- `content` (str): OSCAL JSON content as a string
- `model_type` (str, optional): OSCAL model type (e.g. "catalog", "profile"). Auto-detected from root key if omitted.

**Returns**: Dictionary with:
- `valid`: Overall validity (true only if all non-skipped levels pass)
- `model_type`: Detected or provided model type
- `levels`: Per-level results with `valid`, `errors`, `warnings`, `skipped`, and `skip_reason`

**Key behaviors**:
- If Level 1 fails, Levels 2-4 are skipped
- If `oscal-cli` is not installed, Level 4 is gracefully skipped
- `mapping-collection` skips Level 3 (trestle does not support it)
- Errors capped at 20 per level

---

### 9. About
**Tool**: `about`

Returns metadata about the MCP server itself.
Expand All @@ -154,11 +183,14 @@ Tools are registered in `main.py` using the FastMCP framework. The `query_oscal_
- **compliance-trestle**: OSCAL Pydantic models and utilities
- **boto3**: AWS SDK (for documentation queries)
- **requests**: HTTP client (for remote Component Definition loading)
- **jsonschema**: JSON Schema validation (transitive dependency)

### Utilities
The `utils.py` module provides shared functionality:
- `OSCALModelType`: Enum of OSCAL model types
- `schema_names`: Mapping of model names to schema file names
- `ROOT_KEY_TO_MODEL_TYPE`: Reverse mapping from JSON root keys to model types
- `load_oscal_json_schema()`: Load bundled OSCAL JSON schemas
- `try_notify_client_error()`: Helper for error notifications
- `verify_package_integrity()`: Package integrity verification

Expand All @@ -169,4 +201,4 @@ Tools respect configuration from `config.py`, including:
- `request_timeout`: Timeout for remote requests
- `knowledge_base_id`: Bedrock Knowledge Base ID
- `aws_profile`: AWS profile for Bedrock queries
- `log_level`: Logging level
- `log_level`: Logging level
21 changes: 21 additions & 0 deletions src/mcp_server_for_oscal/tools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,27 @@ class OSCALModelType(StrEnum):
"complete": "oscal_complete_schema",
}

# Maps the root JSON key in an OSCAL document to its model type.
# Used for auto-detecting the model type from document content.
ROOT_KEY_TO_MODEL_TYPE: dict[str, OSCALModelType] = {
mt.value: mt for mt in OSCALModelType
}


def load_oscal_json_schema(model_type: OSCALModelType) -> dict:
"""Load and parse a bundled OSCAL JSON schema by model type.

Args:
model_type: The OSCAL model type to load the schema for.

Returns:
The parsed JSON schema as a dict.
"""
schema_base = schema_names[model_type]
schema_path = Path(__file__).parent.parent / "oscal_schemas" / f"{schema_base}.json"
with open(schema_path) as f:
return json.load(f)


def try_notify_client_error(msg: str, ctx: Context) -> None:
safe_log_mcp(msg, ctx, "error")
Expand Down
Loading