mcp-server-for-oscal 0.1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_server_for_oscal/__init__.py +0 -0
- mcp_server_for_oscal/__main__.py +7 -0
- mcp_server_for_oscal/config.py +72 -0
- mcp_server_for_oscal/main.py +131 -0
- mcp_server_for_oscal/oscal_agent.py +40 -0
- mcp_server_for_oscal/oscal_docs/awesome-oscal.md +181 -0
- mcp_server_for_oscal/oscal_schemas/README.md +116 -0
- mcp_server_for_oscal/oscal_schemas/oscal_assessment-plan_schema.json +1 -0
- mcp_server_for_oscal/oscal_schemas/oscal_assessment-plan_schema.xsd +5268 -0
- mcp_server_for_oscal/oscal_schemas/oscal_assessment-results_schema.json +1 -0
- mcp_server_for_oscal/oscal_schemas/oscal_assessment-results_schema.xsd +5555 -0
- mcp_server_for_oscal/oscal_schemas/oscal_catalog_schema.json +1 -0
- mcp_server_for_oscal/oscal_schemas/oscal_catalog_schema.xsd +2071 -0
- mcp_server_for_oscal/oscal_schemas/oscal_complete_schema.json +1 -0
- mcp_server_for_oscal/oscal_schemas/oscal_complete_schema.xsd +9326 -0
- mcp_server_for_oscal/oscal_schemas/oscal_component_schema.json +1 -0
- mcp_server_for_oscal/oscal_schemas/oscal_component_schema.xsd +3011 -0
- mcp_server_for_oscal/oscal_schemas/oscal_mapping_schema.json +1 -0
- mcp_server_for_oscal/oscal_schemas/oscal_mapping_schema.xsd +2226 -0
- mcp_server_for_oscal/oscal_schemas/oscal_poam_schema.json +1 -0
- mcp_server_for_oscal/oscal_schemas/oscal_poam_schema.xsd +5406 -0
- mcp_server_for_oscal/oscal_schemas/oscal_profile_schema.json +1 -0
- mcp_server_for_oscal/oscal_schemas/oscal_profile_schema.xsd +2493 -0
- mcp_server_for_oscal/oscal_schemas/oscal_ssp_schema.json +1 -0
- mcp_server_for_oscal/oscal_schemas/oscal_ssp_schema.xsd +3945 -0
- mcp_server_for_oscal/py.typed +0 -0
- mcp_server_for_oscal/tools/__init__.py +5 -0
- mcp_server_for_oscal/tools/get_schema.py +101 -0
- mcp_server_for_oscal/tools/list_models.py +79 -0
- mcp_server_for_oscal/tools/list_oscal_resources.py +123 -0
- mcp_server_for_oscal/tools/query_documentation.py +75 -0
- mcp_server_for_oscal/tools/utils.py +37 -0
- mcp_server_for_oscal-0.1.5.dist-info/METADATA +137 -0
- mcp_server_for_oscal-0.1.5.dist-info/RECORD +38 -0
- mcp_server_for_oscal-0.1.5.dist-info/WHEEL +4 -0
- mcp_server_for_oscal-0.1.5.dist-info/entry_points.txt +2 -0
- mcp_server_for_oscal-0.1.5.dist-info/licenses/LICENSE +175 -0
- mcp_server_for_oscal-0.1.5.dist-info/licenses/NOTICE +1 -0
|
File without changes
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool for retrieving OSCAL schemas.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import json
|
|
7
|
+
import logging
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from mcp.server.fastmcp.server import Context
|
|
12
|
+
from strands import tool
|
|
13
|
+
|
|
14
|
+
from mcp_server_for_oscal.tools.utils import OSCALModelType, schema_names
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@tool
|
|
20
|
+
def get_oscal_schema(
|
|
21
|
+
ctx: Context, model_name: str = "complete", schema_type: str = "json"
|
|
22
|
+
) -> str:
|
|
23
|
+
"""
|
|
24
|
+
A tool that returns the schema for specified OSCAL model. Try this tool first for any questions about the structure of OSCAL models.
|
|
25
|
+
By default we return a JSON schema, but `schema_type` parameter can change that behavior. You can use the list_models tool to get
|
|
26
|
+
a list of valid model names.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
ctx: MCP server context (should be injected automatically by MCP server)
|
|
30
|
+
model_name: The name of the OSCAL model. If no value is provided, then we return a "complete" schema including all models, which is large.
|
|
31
|
+
schema_type: If `json` (default) then return the JSON schema for the specified model. Otherwise, return its XSD (XML) schema.
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
str: The requested schema as JSON string
|
|
35
|
+
"""
|
|
36
|
+
logger.debug(
|
|
37
|
+
"get_oscal_model_schema(model_name: %s, syntax: %s, session client params: %s)",
|
|
38
|
+
model_name,
|
|
39
|
+
schema_type,
|
|
40
|
+
ctx.session.client_params,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
if schema_type not in ["json", "xsd"]:
|
|
44
|
+
msg = f"Invalid schema type: {schema_type}."
|
|
45
|
+
if ctx is not None:
|
|
46
|
+
try:
|
|
47
|
+
loop = asyncio.get_running_loop()
|
|
48
|
+
# Already in async context - can't use asyncio.run()
|
|
49
|
+
loop.run_until_complete(ctx.error(msg))
|
|
50
|
+
except RuntimeError:
|
|
51
|
+
# Not in async context - safe to use asyncio.run()
|
|
52
|
+
asyncio.run(ctx.error(msg))
|
|
53
|
+
raise ValueError(msg)
|
|
54
|
+
|
|
55
|
+
if (
|
|
56
|
+
model_name not in OSCALModelType.__members__.values()
|
|
57
|
+
and model_name != "complete"
|
|
58
|
+
):
|
|
59
|
+
msg = f"Invalid model: {model_name}. Use the tool list_oscal_models to get valid model names."
|
|
60
|
+
if ctx is not None:
|
|
61
|
+
try:
|
|
62
|
+
loop = asyncio.get_running_loop()
|
|
63
|
+
# Already in async context - can't use asyncio.run()
|
|
64
|
+
loop.run_until_complete(ctx.error(msg))
|
|
65
|
+
except RuntimeError:
|
|
66
|
+
# Not in async context - safe to use asyncio.run()
|
|
67
|
+
asyncio.run(ctx.error(msg))
|
|
68
|
+
raise ValueError(msg)
|
|
69
|
+
|
|
70
|
+
schema_file_name = f"{schema_names.get(model_name)}.{schema_type}"
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
schema = json.load(open_schema_file(schema_file_name))
|
|
74
|
+
except Exception:
|
|
75
|
+
msg = f"failed to open schema {schema_file_name}"
|
|
76
|
+
logger.exception(msg)
|
|
77
|
+
if ctx is not None:
|
|
78
|
+
try:
|
|
79
|
+
loop = asyncio.get_running_loop()
|
|
80
|
+
# Already in async context - can't use asyncio.run()
|
|
81
|
+
loop.run_until_complete(ctx.error(msg))
|
|
82
|
+
except RuntimeError:
|
|
83
|
+
# Not in async context - safe to use asyncio.run()
|
|
84
|
+
asyncio.run(ctx.error(msg))
|
|
85
|
+
raise
|
|
86
|
+
|
|
87
|
+
return json.dumps(schema)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def open_schema_file(file_name: str) -> Any:
|
|
91
|
+
"""Open a schema file from the OSCAL schemas directory."""
|
|
92
|
+
# Get the directory of this file and navigate to oscal_schemas relative to it
|
|
93
|
+
current_file_dir = Path(__file__).parent
|
|
94
|
+
schema_path = current_file_dir.parent.joinpath("oscal_schemas")
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
return open(schema_path.joinpath(file_name.lstrip("./\\")))
|
|
98
|
+
except Exception:
|
|
99
|
+
msg = f"failed to open file {file_name}"
|
|
100
|
+
logger.exception(msg)
|
|
101
|
+
raise
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool for listing available OSCAL model types.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from strands import tool
|
|
6
|
+
|
|
7
|
+
from mcp_server_for_oscal.tools.utils import OSCALModelType
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@tool
|
|
11
|
+
def list_oscal_models() -> dict:
|
|
12
|
+
"""
|
|
13
|
+
List all available OSCAL model types with metadata.
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
dict: List of OSCAL models where the key is model's name as used
|
|
17
|
+
in the schema, and value is an object that includes description,
|
|
18
|
+
layer, formal and short names, and release status.
|
|
19
|
+
"""
|
|
20
|
+
models = {
|
|
21
|
+
OSCALModelType.CATALOG: {
|
|
22
|
+
"description": "A structured set of controls and control enhancements",
|
|
23
|
+
"layer": "Control",
|
|
24
|
+
"formalName": "Catalog",
|
|
25
|
+
"shortName": "catalog",
|
|
26
|
+
"status": "GA",
|
|
27
|
+
},
|
|
28
|
+
OSCALModelType.PROFILE: {
|
|
29
|
+
"description": "A baseline or overlay that selects and customizes controls from catalogs",
|
|
30
|
+
"layer": "Control",
|
|
31
|
+
"formalName": "Profile",
|
|
32
|
+
"shortName": "profile",
|
|
33
|
+
"status": "GA",
|
|
34
|
+
},
|
|
35
|
+
OSCALModelType.MAPPING: {
|
|
36
|
+
"description": "Describes how a collection of security controls relates to another collection of controls",
|
|
37
|
+
"layer": "Control",
|
|
38
|
+
"formalName": "Mapping Collection",
|
|
39
|
+
"shortName": "mapping",
|
|
40
|
+
"status": "GA",
|
|
41
|
+
},
|
|
42
|
+
OSCALModelType.COMPONENT_DEFINITION: {
|
|
43
|
+
"description": "Describes how components implement controls",
|
|
44
|
+
"layer": "Implementation",
|
|
45
|
+
"formalName": "Component Definition",
|
|
46
|
+
"shortName": "component",
|
|
47
|
+
"status": "GA",
|
|
48
|
+
},
|
|
49
|
+
OSCALModelType.SYSTEM_SECURITY_PLAN: {
|
|
50
|
+
"description": "Documents how a system implements required controls",
|
|
51
|
+
"layer": "Implementation",
|
|
52
|
+
"formalName": "System Security Plan (SSP)",
|
|
53
|
+
"shortName": "SSP",
|
|
54
|
+
"status": "GA",
|
|
55
|
+
},
|
|
56
|
+
OSCALModelType.ASSESSMENT_PLAN: {
|
|
57
|
+
"description": "Defines how controls will be assessed",
|
|
58
|
+
"layer": "Assessment",
|
|
59
|
+
"formalName": "Security Assessment Plan (SAP)",
|
|
60
|
+
"shortName": "AP",
|
|
61
|
+
"status": "GA",
|
|
62
|
+
},
|
|
63
|
+
OSCALModelType.ASSESSMENT_RESULTS: {
|
|
64
|
+
"description": "Documents the results of control assessments",
|
|
65
|
+
"layer": "Assessment",
|
|
66
|
+
"formalName": "Security Assessment Results (SAR)",
|
|
67
|
+
"shortName": "AR",
|
|
68
|
+
"status": "GA",
|
|
69
|
+
},
|
|
70
|
+
OSCALModelType.PLAN_OF_ACTION_AND_MILESTONES: {
|
|
71
|
+
"description": "Documents remediation plans for identified issues",
|
|
72
|
+
"layer": "Assessment",
|
|
73
|
+
"formalName": "Plan of Action and Milestones (POA&M)",
|
|
74
|
+
"shortName": "POAM",
|
|
75
|
+
"status": "GA",
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return models
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool for listing OSCAL community resources.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import asyncio
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from mcp.server.fastmcp.server import Context
|
|
11
|
+
from strands import tool
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@tool
|
|
17
|
+
def list_oscal_resources(ctx: Context) -> str:
|
|
18
|
+
"""
|
|
19
|
+
Retrieve a comprehensive directory of OSCAL community resources and tools.
|
|
20
|
+
|
|
21
|
+
This tool provides access to a curated collection of OSCAL (Open Security Controls Assessment Language)
|
|
22
|
+
community resources that can help users:
|
|
23
|
+
|
|
24
|
+
- Find OSCAL-compatible tools and software implementations
|
|
25
|
+
- Discover educational content, tutorials, and documentation
|
|
26
|
+
- Access example OSCAL documents and templates
|
|
27
|
+
- Locate presentations, articles, and research papers about OSCAL
|
|
28
|
+
- Identify government and industry adoption examples
|
|
29
|
+
- Find libraries and SDKs for OSCAL development
|
|
30
|
+
- Access validation tools and utilities
|
|
31
|
+
|
|
32
|
+
The returned content is structured markdown that categorizes resources by type (tools, content,
|
|
33
|
+
presentations, etc.) making it easy to find specific types of OSCAL resources based on user needs.
|
|
34
|
+
|
|
35
|
+
Use this tool when users ask about:
|
|
36
|
+
- "What OSCAL tools are available?"
|
|
37
|
+
- "How can I learn more about OSCAL?"
|
|
38
|
+
- "Are there examples of OSCAL implementations?"
|
|
39
|
+
- "What resources exist for OSCAL development?"
|
|
40
|
+
- "Who is using OSCAL in production?"
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
ctx: MCP server context (should be injected automatically by MCP server)
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
str: Complete markdown content containing categorized OSCAL community resources,
|
|
47
|
+
tools, documentation, examples, and educational materials
|
|
48
|
+
|
|
49
|
+
Raises:
|
|
50
|
+
FileNotFoundError: If the awesome-oscal.md file cannot be found
|
|
51
|
+
IOError: If there are issues reading the file
|
|
52
|
+
UnicodeDecodeError: If there are encoding issues with the file
|
|
53
|
+
"""
|
|
54
|
+
logger.debug(
|
|
55
|
+
"list_oscal_resources() called with session client params: %s",
|
|
56
|
+
ctx.session.client_params if ctx else None,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
content = read_resources_file()
|
|
61
|
+
logger.debug("Successfully read OSCAL resources file")
|
|
62
|
+
return content
|
|
63
|
+
except Exception:
|
|
64
|
+
msg = "Failed to read OSCAL resources file."
|
|
65
|
+
logger.exception(msg)
|
|
66
|
+
if ctx is not None:
|
|
67
|
+
try:
|
|
68
|
+
loop = asyncio.get_running_loop()
|
|
69
|
+
# Already in async context - can't use asyncio.run()
|
|
70
|
+
loop.run_until_complete(ctx.error(msg))
|
|
71
|
+
except RuntimeError:
|
|
72
|
+
# Not in async context - safe to use asyncio.run()
|
|
73
|
+
result = asyncio.run(ctx.error(msg))
|
|
74
|
+
raise
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def read_resources_file() -> str:
|
|
78
|
+
"""
|
|
79
|
+
Read the awesome-oscal.md file from the oscal_docs directory.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
str: The complete content of the awesome-oscal.md file
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
FileNotFoundError: If the awesome-oscal.md file cannot be found
|
|
86
|
+
IOError: If there are issues reading the file
|
|
87
|
+
UnicodeDecodeError: If there are encoding issues with the file
|
|
88
|
+
"""
|
|
89
|
+
# Get the directory of this file and navigate to oscal_docs relative to it
|
|
90
|
+
current_file_dir = Path(__file__).parent
|
|
91
|
+
docs_path = current_file_dir.parent / "oscal_docs"
|
|
92
|
+
resources_file_path = docs_path / "awesome-oscal.md"
|
|
93
|
+
|
|
94
|
+
logger.debug("Reading OSCAL resources from: %s", resources_file_path)
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
# Read with explicit UTF-8 encoding and error handling
|
|
98
|
+
with open(resources_file_path, "r", encoding="utf-8", errors="strict") as file:
|
|
99
|
+
content = file.read()
|
|
100
|
+
|
|
101
|
+
if not content.strip():
|
|
102
|
+
logger.warning("OSCAL resources file is empty")
|
|
103
|
+
|
|
104
|
+
return content
|
|
105
|
+
except FileNotFoundError:
|
|
106
|
+
logger.error("OSCAL resources file not found at: %s", resources_file_path)
|
|
107
|
+
raise
|
|
108
|
+
except UnicodeDecodeError as e:
|
|
109
|
+
logger.error("Encoding error reading file %s: %s", resources_file_path, e)
|
|
110
|
+
# Try with different encoding as fallback
|
|
111
|
+
try:
|
|
112
|
+
with open(
|
|
113
|
+
resources_file_path, "r", encoding="latin-1", errors="replace"
|
|
114
|
+
) as file:
|
|
115
|
+
content = file.read()
|
|
116
|
+
logger.warning("Successfully read file with latin-1 encoding fallback")
|
|
117
|
+
return content
|
|
118
|
+
except Exception as fallback_error:
|
|
119
|
+
logger.error("Fallback encoding also failed: %s", fallback_error)
|
|
120
|
+
raise e # Raise the original UnicodeDecodeError
|
|
121
|
+
except (IOError, OSError) as e:
|
|
122
|
+
logger.error("IO error reading file %s: %s", resources_file_path, e)
|
|
123
|
+
raise
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool for querying OSCAL documentation from Amazon Bedrock Knowledge Base.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from boto3 import Session
|
|
10
|
+
from mcp.server.fastmcp.server import Context
|
|
11
|
+
from strands import tool
|
|
12
|
+
|
|
13
|
+
from mcp_server_for_oscal.config import config
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
logger.setLevel(config.log_level)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@tool
|
|
20
|
+
def query_oscal_documentation(query: str, ctx: Context) -> Any:
|
|
21
|
+
"""
|
|
22
|
+
A tool to query OSCAL-related documentation. Use this tool when a question about OSCAL cannot be answered just by analyzing model schemas. In case the question is about an explicit property of an OSCAL model, try to find the answer using the get_schema tool first.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
query: Question or search query about OSCAL
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
dict: Results retrieved from knowledge base, structured as a Bedrock RetrieveResponseTypeDef object.
|
|
29
|
+
"""
|
|
30
|
+
if config.knowledge_base_id is None:
|
|
31
|
+
msg = "Knowledge base ID is not set. Please set the OSCAL_KB_ID environment variable."
|
|
32
|
+
logger.warning(msg)
|
|
33
|
+
if ctx is not None:
|
|
34
|
+
garbage = ctx.warning(msg)
|
|
35
|
+
return query_local(query, ctx)
|
|
36
|
+
return query_kb(query, ctx)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def query_kb(query: str, ctx: Context) -> Any:
|
|
40
|
+
"""Query Amazon Bedrock Knowledgebase using Boto SDK."""
|
|
41
|
+
try:
|
|
42
|
+
# Initialize boto session with the configured profile
|
|
43
|
+
aws_profile = config.aws_profile
|
|
44
|
+
if aws_profile:
|
|
45
|
+
logger.debug(f"Using AWS profile: {aws_profile}")
|
|
46
|
+
s = Session(profile_name=aws_profile)
|
|
47
|
+
else:
|
|
48
|
+
logger.debug("Using default AWS profile or environment credentials")
|
|
49
|
+
s = Session()
|
|
50
|
+
|
|
51
|
+
# Query Amazon Bedrock Knowledgebase using Boto SDK
|
|
52
|
+
answer = s.client("bedrock-agent-runtime").retrieve(
|
|
53
|
+
knowledgeBaseId=config.knowledge_base_id, retrievalQuery={"text": query}
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
logger.debug(json.dumps(answer, indent=1))
|
|
57
|
+
|
|
58
|
+
return answer
|
|
59
|
+
|
|
60
|
+
except Exception as e:
|
|
61
|
+
msg = f"Error running query {query} documentation: {e}"
|
|
62
|
+
logger.exception(msg)
|
|
63
|
+
if ctx is not None:
|
|
64
|
+
garbage = ctx.error(msg)
|
|
65
|
+
raise
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def query_local(query: str, ctx: Context) -> Any:
|
|
69
|
+
msg = "Not yet implemented"
|
|
70
|
+
logger.error(msg)
|
|
71
|
+
if ctx is not None:
|
|
72
|
+
garbage = ctx.error(msg)
|
|
73
|
+
return {
|
|
74
|
+
"error": msg,
|
|
75
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Shared utilities for OSCAL MCP tools.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
# import os.path
|
|
6
|
+
import logging
|
|
7
|
+
|
|
8
|
+
# from typing import Any
|
|
9
|
+
from enum import StrEnum
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class OSCALModelType(StrEnum):
|
|
15
|
+
"""Enumeration of OSCAL model types."""
|
|
16
|
+
# These values are intended to match the root object name in the JSON schema
|
|
17
|
+
CATALOG = "catalog"
|
|
18
|
+
PROFILE = "profile"
|
|
19
|
+
COMPONENT_DEFINITION = "component-definition"
|
|
20
|
+
SYSTEM_SECURITY_PLAN = "system-security-plan"
|
|
21
|
+
ASSESSMENT_PLAN = "assessment-plan"
|
|
22
|
+
ASSESSMENT_RESULTS = "assessment-results"
|
|
23
|
+
PLAN_OF_ACTION_AND_MILESTONES = "plan-of-action-and-milestones"
|
|
24
|
+
MAPPING = "mapping-collection"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
schema_names = {
|
|
28
|
+
OSCALModelType.ASSESSMENT_PLAN: "oscal_assessment-plan_schema",
|
|
29
|
+
OSCALModelType.ASSESSMENT_RESULTS: "oscal_assessment-results_schema",
|
|
30
|
+
OSCALModelType.CATALOG: "oscal_catalog_schema",
|
|
31
|
+
OSCALModelType.COMPONENT_DEFINITION: "oscal_component_schema",
|
|
32
|
+
OSCALModelType.MAPPING: "oscal_mapping_schema",
|
|
33
|
+
OSCALModelType.PROFILE: "oscal_profile_schema",
|
|
34
|
+
OSCALModelType.PLAN_OF_ACTION_AND_MILESTONES: "oscal_poam_schema",
|
|
35
|
+
OSCALModelType.SYSTEM_SECURITY_PLAN: "oscal_ssp_schema",
|
|
36
|
+
"complete": "oscal_complete_schema"
|
|
37
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mcp-server-for-oscal
|
|
3
|
+
Version: 0.1.5
|
|
4
|
+
Summary: AI agent tools for Open Security Controls Assessment Language (OSCAL).
|
|
5
|
+
License-File: LICENSE
|
|
6
|
+
License-File: NOTICE
|
|
7
|
+
Requires-Python: >=3.11
|
|
8
|
+
Requires-Dist: boto3>=1.42.7
|
|
9
|
+
Requires-Dist: mcp>=1.23.3
|
|
10
|
+
Requires-Dist: strands-agents>=1.19.0
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# MCP Server for OSCAL
|
|
14
|
+
|
|
15
|
+
A Model Context Protocol (MCP) server that provides AI assistants (Claude, Cline, Kiro, Claude Code, etc.) with tools to work with NIST's Open Security Controls Assessment Language (OSCAL). Like many early adopters, we needed help implementing OSCAL proofs-of-concept to demonstrate value to business stakeholders. Perhaps due to limited availability of examples in the public domain, we found that most AI agents/LLMs alone produced inconsistent results related to OSCAL. The tools in this MCP server minimzed that problem for our use-case and we hope they do the same for you.
|
|
16
|
+
|
|
17
|
+
## What is OSCAL?
|
|
18
|
+
|
|
19
|
+
[OSCAL (Open Security Controls Assessment Language)](https://pages.nist.gov/OSCAL/) is a set of framework-agnostic, vendor-neutral, machine-readable schemas developed by NIST that describe the full life cycle of GRC (governance, risk, compliance) artifacts, from controls to remediation plans. OSCAL enables automation of GRC workflows by replacing digital paper (spreadsheets, PDFs, etc.) with a standard-based structured data format.
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
This MCP server provides [tools](src/mcp_server_for_oscal/tools/) for working with OSCAL:
|
|
23
|
+
|
|
24
|
+
### 1. List OSCAL Models
|
|
25
|
+
- **Tool**: `list_oscal_models`
|
|
26
|
+
- Retrieve all available OSCAL model types with descriptions, layers, and status
|
|
27
|
+
- Understand the different OSCAL models and their purposes
|
|
28
|
+
|
|
29
|
+
### 2. Get OSCAL Schemas
|
|
30
|
+
- **Tool**: `get_oscal_schema`
|
|
31
|
+
- Retrieve JSON or XSD schemas for current GA release of individual OSCAL models. Because OSCAL schemas are self-documenting, this is equivalent to querying model documentation.
|
|
32
|
+
- Used to answer questions about the structure, properties, requirements of each OSCAL model
|
|
33
|
+
|
|
34
|
+
### 3. List OSCAL Community Resources
|
|
35
|
+
- **Tool**: `list_oscal_resources`
|
|
36
|
+
- Access a curated collection of OSCAL community resources from [Awesome OSCAL](https://github.com/oscal-club/awesome-oscal)
|
|
37
|
+
- Get information about available OSCAL tools, content, articles, presentations, and educational materials
|
|
38
|
+
- Includes resources from government agencies, security organizations, and the broader OSCAL community
|
|
39
|
+
|
|
40
|
+
### 4. Query OSCAL Documentation
|
|
41
|
+
- **Tool**: `query_oscal_documentation`
|
|
42
|
+
- Query authoritative OSCAL documentation using Amazon Bedrock Knowledge Base (KB). Note that this feature requires you to setup and maintain a Bedrock KB in your AWS account. In future, we hope to provide this as a service.
|
|
43
|
+
- Get answers to questions about OSCAL concepts, best practices, and implementation guidance.
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
If you just want to use the MCP server with your IDE or preferred AI tool, then you don't need to clone the project or download source code.
|
|
47
|
+
### Prerequisites
|
|
48
|
+
|
|
49
|
+
- `uv` package manager for Python [(Installation instructions)](https://docs.astral.sh/uv/getting-started/installation/)
|
|
50
|
+
- Python 3.11 or higher; [(`uv install python 3.12`)](https://docs.astral.sh/uv/guides/install-python/). The server may work with other versions of Python, but we only test 3.11 & 3.12 for now.
|
|
51
|
+
|
|
52
|
+
### Configuring IDEs and AI Tools
|
|
53
|
+
|
|
54
|
+
This MCP server communicates via stdio (standard input/output) and can be integrated with various IDEs and agentic tools that support the Model Context Protocol.
|
|
55
|
+
|
|
56
|
+
#### Configuration Format
|
|
57
|
+
|
|
58
|
+
Most MCP-compatible tools use a JSON configuration format described in the [FastMCP documentation](https://gofastmcp.com/integrations/mcp-json-configuration). Here's the basic structure:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"mcpServers": {
|
|
63
|
+
"oscal": {
|
|
64
|
+
"command": "uvx",
|
|
65
|
+
"args": ["--from", "mcp-server-for-oscal@latest", "server"],
|
|
66
|
+
"env": {
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### IDE-Specific Configuration
|
|
74
|
+
|
|
75
|
+
**Kiro IDE**
|
|
76
|
+
See [Kiro's MCP documentation](https://kiro.dev/docs/mcp/configuration/) for additional options. Add to your `.kiro/settings/mcp.json`:
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"mcpServers": {
|
|
81
|
+
"oscal": {
|
|
82
|
+
"command": "uvx",
|
|
83
|
+
"args": ["--from", "mcp-server-for-oscal@latest", "server"],
|
|
84
|
+
"env": {},
|
|
85
|
+
"disabled": false,
|
|
86
|
+
"autoApprove": [
|
|
87
|
+
"get_oscal_schema",
|
|
88
|
+
"list_oscal_resources",
|
|
89
|
+
"list_oscal_models",
|
|
90
|
+
"query_oscal_documentation"
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Claude Desktop**
|
|
98
|
+
Add to your `~/.claude/claude_desktop_config.json`:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"mcpServers": {
|
|
103
|
+
"oscal": {
|
|
104
|
+
"command": "uvx",
|
|
105
|
+
"args": ["--from", "mcp-server-for-oscal@latest", "server"]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**VS Code**
|
|
112
|
+
Run the `MCP: Open User Configuration` command, which opens the mcp.json file in your user profile. You can then manually add the server configuration to the file. See the [VSCode/Copilot docs](https://code.visualstudio.com/docs/copilot/customization/mcp-servers#_add-an-mcp-server) for addtional options and details.
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"servers": [
|
|
117
|
+
"oscal": {
|
|
118
|
+
"command": "uvx",
|
|
119
|
+
"args": ["--from", "mcp-server-for-oscal@latest", "server"]
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Environment Variables
|
|
126
|
+
Generally, configuration should not be required. See the file [dotenv.example](dotenv.example) for available options. Note that a dotenv file is only needed in a development environment. For typical, runtime use of the MCP server, environment variables should be configured as described in the [FastMCP documentation](https://gofastmcp.com/integrations/mcp-json-configuration#env-optional).
|
|
127
|
+
|
|
128
|
+
## Development
|
|
129
|
+
See [DEVELOPING](DEVELOPING.md) to get started.
|
|
130
|
+
|
|
131
|
+
## Security
|
|
132
|
+
|
|
133
|
+
See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
This project is licensed under the [Apache-2.0](LICENSE) License.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
mcp_server_for_oscal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
mcp_server_for_oscal/__main__.py,sha256=qrmsifNBPjwmKSrpdCdLgk9EffBmy4LpvQ9X_aAZxVM,170
|
|
3
|
+
mcp_server_for_oscal/config.py,sha256=zQx0KVC_wVIBRP0ClD0NpoUd2uH126VuHCRcoKPSuRU,2340
|
|
4
|
+
mcp_server_for_oscal/main.py,sha256=G89YH78KmD_C5dD4n_iIUKX5d880-ulf0stkcaapO-M,4275
|
|
5
|
+
mcp_server_for_oscal/oscal_agent.py,sha256=zSEusbCh6oQGzC0dfOvgMh4HiChufVKxtk2dYelK-Ac,1424
|
|
6
|
+
mcp_server_for_oscal/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
mcp_server_for_oscal/oscal_docs/awesome-oscal.md,sha256=QQXcXMfw9pnx1EKOEa7sKNq2cYBtSOW0gLY-8Qj8kd4,20684
|
|
8
|
+
mcp_server_for_oscal/oscal_schemas/README.md,sha256=QOiuHFR6aJoCddNAqC1ha7ZZj53RGMfKi9GMw-fGWo4,4672
|
|
9
|
+
mcp_server_for_oscal/oscal_schemas/oscal_assessment-plan_schema.json,sha256=ILvWO55KGslPlIb-b86AEgR99uuw8iv4R39WYGUalTc,105944
|
|
10
|
+
mcp_server_for_oscal/oscal_schemas/oscal_assessment-plan_schema.xsd,sha256=eBjC_nSqUWXZZHYCyddL_uF65q9dflcDy9bmdsY0KnE,318162
|
|
11
|
+
mcp_server_for_oscal/oscal_schemas/oscal_assessment-results_schema.json,sha256=VHkA2AdK_RRLtHsEOh3rCPwsZKDgB5zBzrypdhjw_2o,111568
|
|
12
|
+
mcp_server_for_oscal/oscal_schemas/oscal_assessment-results_schema.xsd,sha256=fuoNIQjuDbq_pHWSgg8hCnUgYiviDGGPPF5FuPk1uzg,337785
|
|
13
|
+
mcp_server_for_oscal/oscal_schemas/oscal_catalog_schema.json,sha256=nZksKELAaXPqswdTdySq8-5tKvVsvsPzlLKflDF2f5w,40440
|
|
14
|
+
mcp_server_for_oscal/oscal_schemas/oscal_catalog_schema.xsd,sha256=I40mYyirjylx9YDpdsIs_EBG1ApkoKwmbaetf4DMcv0,111511
|
|
15
|
+
mcp_server_for_oscal/oscal_schemas/oscal_complete_schema.json,sha256=hKFCbaiKfC_n8dQd1jMh-GTLA-LrUlawlnmtZdimaD8,202768
|
|
16
|
+
mcp_server_for_oscal/oscal_schemas/oscal_complete_schema.xsd,sha256=MfOgKjgx4gUfr1VimRZaRniz1mGRDTOX_2wdI0l8J-U,567360
|
|
17
|
+
mcp_server_for_oscal/oscal_schemas/oscal_component_schema.json,sha256=Em6kfd6V_e0pSbGGJMvM3WFKaa8nozdTdAYyKI1MWls,61961
|
|
18
|
+
mcp_server_for_oscal/oscal_schemas/oscal_component_schema.xsd,sha256=fXxXBrbFZ6kXOCXO2wsSeZgQ93Oww_8vhPjFd3s0egU,169052
|
|
19
|
+
mcp_server_for_oscal/oscal_schemas/oscal_mapping_schema.json,sha256=Avm8PDxknE3co33ZzHmKENNO3_bkODnH7cwiBu2nchs,43295
|
|
20
|
+
mcp_server_for_oscal/oscal_schemas/oscal_mapping_schema.xsd,sha256=pRSGdZkJJ0UqtdjQhFbGDSIMgAltf88cNB1W8qj2das,123704
|
|
21
|
+
mcp_server_for_oscal/oscal_schemas/oscal_poam_schema.json,sha256=U8C9jOOHxd9ZPbtYX0oOE_C7JDDgzCHsxKUWw4i4n9w,108642
|
|
22
|
+
mcp_server_for_oscal/oscal_schemas/oscal_poam_schema.xsd,sha256=fr2pKmmK96ANEjr02gqJC8NzkOOu5UCbD4vQkJdXf1o,326269
|
|
23
|
+
mcp_server_for_oscal/oscal_schemas/oscal_profile_schema.json,sha256=hUwSfnXhzu_o0s1hRUfZOkbDNAdBkgQ5hW_ReQXPJjI,49871
|
|
24
|
+
mcp_server_for_oscal/oscal_schemas/oscal_profile_schema.xsd,sha256=N09ONO-eSapidl3C7KZmgZbeT4LBTvVLkTrgMnRy0ek,136763
|
|
25
|
+
mcp_server_for_oscal/oscal_schemas/oscal_ssp_schema.json,sha256=WrWfNHHlPxUHPEGJcjjx0XATvZhUF7Z5C78R4TrgB30,80359
|
|
26
|
+
mcp_server_for_oscal/oscal_schemas/oscal_ssp_schema.xsd,sha256=VzJ845-ZEiQKAPM39jXq5pi_StgrXpmX6w27zhpYfxE,237445
|
|
27
|
+
mcp_server_for_oscal/tools/__init__.py,sha256=bq10TtkxFCTpTTLsz-9OPoTsANdQS9gy6nH6Qi8iNpg,103
|
|
28
|
+
mcp_server_for_oscal/tools/get_schema.py,sha256=x0LyU2gYD4K1YB_ZZpohpqvsT99l0eROrJrgebWudOo,3644
|
|
29
|
+
mcp_server_for_oscal/tools/list_models.py,sha256=yvs3n1hVb0uMCsC61jd5_qyPDoud2mhzXtFhsSMj2R4,2829
|
|
30
|
+
mcp_server_for_oscal/tools/list_oscal_resources.py,sha256=KvoE_L-rdA_O9uOlLblKNMtrk93zBgy8bR7i6yGVsno,4595
|
|
31
|
+
mcp_server_for_oscal/tools/query_documentation.py,sha256=rTsr8pzJ-kjWRFJLsgEI5vHPiYneze8ATlOOSgdfou8,2372
|
|
32
|
+
mcp_server_for_oscal/tools/utils.py,sha256=SSpwh-Vd01IQSm19pW4Iffw_kYU78TYQlOw1qlfKTnw,1221
|
|
33
|
+
mcp_server_for_oscal-0.1.5.dist-info/METADATA,sha256=PupTPUP88c8tZySfAuTKHTMLLMDaYLJOrhD6N8IQRzc,5816
|
|
34
|
+
mcp_server_for_oscal-0.1.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
35
|
+
mcp_server_for_oscal-0.1.5.dist-info/entry_points.txt,sha256=V2fi4mxQL6L1jEQPi2Vt0UpJhqZ-NPmTf3sQbHlg0io,58
|
|
36
|
+
mcp_server_for_oscal-0.1.5.dist-info/licenses/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
|
|
37
|
+
mcp_server_for_oscal-0.1.5.dist-info/licenses/NOTICE,sha256=1CkO1kwu3Q_OHYTj-d-yiBJA_lNN73a4zSntavaD4oc,67
|
|
38
|
+
mcp_server_for_oscal-0.1.5.dist-info/RECORD,,
|