cloudwright-ai-mcp 0.3.1__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.
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: cloudwright-ai-mcp
3
+ Version: 0.3.1
4
+ Summary: MCP server for Cloudwright architecture intelligence
5
+ Project-URL: Homepage, https://github.com/xmpuspus/cloudwright
6
+ Author: Xavier Puspus
7
+ License-Expression: MIT
8
+ Requires-Python: >=3.12
9
+ Requires-Dist: cloudwright-ai<1,>=0.3.0
10
+ Requires-Dist: mcp<2,>=1.12
@@ -0,0 +1,14 @@
1
+ cloudwright_mcp/__init__.py,sha256=r4xAFihOf72W9TD-lpMi6ntWSTKTP2SlzKP1ytkjRbI,22
2
+ cloudwright_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ cloudwright_mcp/serializers.py,sha256=z8jFqt3XXnBmQYQl5gvqzw6jyd7DTOqRKhgNyIr1RmY,567
4
+ cloudwright_mcp/server.py,sha256=oYwh6ACIVXWwUfIhvabgTnOAAx7lM0bkmNOXQ9WLnv0,888
5
+ cloudwright_mcp/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ cloudwright_mcp/tools/analyze.py,sha256=I11EyDjSiLzHawwbmz-arOLOw_X03iwjQc-0n7ps0X8,1566
7
+ cloudwright_mcp/tools/cost.py,sha256=DQ7p9HBcATrPS6n7q2rAxlKSiR5fvkMKaXgydID0cws,1004
8
+ cloudwright_mcp/tools/design.py,sha256=UIJx1DqM8UF7zlEj0TW0w0CjyzCsGMR2fgb-5qMkkFQ,1814
9
+ cloudwright_mcp/tools/export.py,sha256=-bk1AeToXkTQ6jrzut4nN8-v3iMmkKsBYZKrgLnkuec,1478
10
+ cloudwright_mcp/tools/session.py,sha256=N-X9ZocqLaZsXVjw5XoiyD-4jvPsjGCct9f4S5tY4Pg,1929
11
+ cloudwright_mcp/tools/validate.py,sha256=WldKq_jGojeJwcZwuF6qp13BPVDmuo9yIVWNC7kb_VY,1954
12
+ cloudwright_ai_mcp-0.3.1.dist-info/METADATA,sha256=kCGj92FK65onK8Y03rBPyYCgJXlKi4xhhpdtH8GSKMo,325
13
+ cloudwright_ai_mcp-0.3.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
14
+ cloudwright_ai_mcp-0.3.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.29.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1 @@
1
+ __version__ = "0.3.1"
File without changes
@@ -0,0 +1,24 @@
1
+ from __future__ import annotations
2
+
3
+ import dataclasses
4
+
5
+
6
+ def security_report_to_dict(report) -> dict:
7
+ return {
8
+ "passed": report.passed,
9
+ "critical_count": report.critical_count,
10
+ "high_count": report.high_count,
11
+ "findings": [dataclasses.asdict(f) for f in report.findings],
12
+ }
13
+
14
+
15
+ def lint_warnings_to_dict(warnings) -> list[dict]:
16
+ return [dataclasses.asdict(w) for w in warnings]
17
+
18
+
19
+ def score_result_to_dict(result) -> dict:
20
+ return result.to_dict()
21
+
22
+
23
+ def analysis_result_to_dict(result) -> dict:
24
+ return result.to_dict()
@@ -0,0 +1,32 @@
1
+ """FastMCP server for Cloudwright architecture intelligence."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from mcp.server.fastmcp import FastMCP
6
+
7
+ from cloudwright_mcp.tools import analyze, cost, design, export, session, validate
8
+
9
+ _GROUPS = {
10
+ "design": design,
11
+ "cost": cost,
12
+ "validate": validate,
13
+ "analyze": analyze,
14
+ "export": export,
15
+ "session": session,
16
+ }
17
+
18
+
19
+ def create_server(tools: set[str] | None = None) -> FastMCP:
20
+ """Create a FastMCP server with selected tool groups.
21
+
22
+ Args:
23
+ tools: Set of group names to register. None = all groups.
24
+ Valid groups: design, cost, validate, analyze, export, session.
25
+ """
26
+ mcp = FastMCP("cloudwright", description="Architecture intelligence for cloud engineers")
27
+
28
+ for name, module in _GROUPS.items():
29
+ if tools is None or name in tools:
30
+ module.register(mcp)
31
+
32
+ return mcp
File without changes
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from mcp.server.fastmcp import FastMCP
4
+
5
+
6
+ def register(mcp: FastMCP) -> None:
7
+ @mcp.tool()
8
+ def analyze_blast_radius(spec_json: dict, component_id: str | None = None) -> dict:
9
+ """Analyze blast radius and dependency structure of an architecture."""
10
+ from cloudwright.analyzer import Analyzer
11
+ from cloudwright.spec import ArchSpec
12
+
13
+ from cloudwright_mcp.serializers import analysis_result_to_dict
14
+
15
+ spec = ArchSpec.model_validate(spec_json)
16
+ result = Analyzer().analyze(spec, component_id=component_id)
17
+ return analysis_result_to_dict(result)
18
+
19
+ @mcp.tool()
20
+ def score_architecture(spec_json: dict) -> dict:
21
+ """Score an architecture across reliability, security, cost, compliance, and complexity."""
22
+ from cloudwright.scorer import Scorer
23
+ from cloudwright.spec import ArchSpec
24
+
25
+ from cloudwright_mcp.serializers import score_result_to_dict
26
+
27
+ spec = ArchSpec.model_validate(spec_json)
28
+ result = Scorer().score(spec)
29
+ return score_result_to_dict(result)
30
+
31
+ @mcp.tool()
32
+ def diff_architectures(old_spec_json: dict, new_spec_json: dict) -> dict:
33
+ """Diff two architecture specs and return a structured change report."""
34
+ from cloudwright.differ import Differ
35
+ from cloudwright.spec import ArchSpec
36
+
37
+ old = ArchSpec.model_validate(old_spec_json)
38
+ new = ArchSpec.model_validate(new_spec_json)
39
+ result = Differ().diff(old, new)
40
+ return result.model_dump(exclude_none=True)
@@ -0,0 +1,25 @@
1
+ from __future__ import annotations
2
+
3
+ from mcp.server.fastmcp import FastMCP
4
+
5
+
6
+ def register(mcp: FastMCP) -> None:
7
+ @mcp.tool()
8
+ def estimate_cost(spec_json: dict, pricing_tier: str = "on_demand") -> dict:
9
+ """Estimate monthly cost for an architecture spec."""
10
+ from cloudwright.cost import CostEngine
11
+ from cloudwright.spec import ArchSpec
12
+
13
+ spec = ArchSpec.model_validate(spec_json)
14
+ estimate = CostEngine().estimate(spec, pricing_tier=pricing_tier)
15
+ return estimate.model_dump(exclude_none=True)
16
+
17
+ @mcp.tool()
18
+ def compare_provider_costs(spec_json: dict, providers: list[str]) -> list[dict]:
19
+ """Compare costs for an architecture across cloud providers."""
20
+ from cloudwright.cost import CostEngine
21
+ from cloudwright.spec import ArchSpec
22
+
23
+ spec = ArchSpec.model_validate(spec_json)
24
+ comparisons = CostEngine().compare_providers(spec, providers)
25
+ return [c.model_dump(exclude_none=True) for c in comparisons]
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ from mcp.server.fastmcp import FastMCP
4
+
5
+
6
+ def register(mcp: FastMCP) -> None:
7
+ @mcp.tool()
8
+ def design_architecture(
9
+ description: str,
10
+ provider: str = "aws",
11
+ region: str = "us-east-1",
12
+ budget_monthly: float | None = None,
13
+ compliance: list[str] | None = None,
14
+ ) -> dict:
15
+ """Design a cloud architecture from a natural language description."""
16
+ from cloudwright.architect import Architect
17
+ from cloudwright.cost import CostEngine
18
+ from cloudwright.spec import Constraints
19
+
20
+ constraints = Constraints(regions=[region], budget_monthly=budget_monthly, compliance=compliance or [])
21
+ spec = Architect().design(description, constraints=constraints)
22
+ if not spec.cost_estimate:
23
+ spec = spec.model_copy(update={"cost_estimate": CostEngine().estimate(spec)})
24
+ return spec.model_dump(exclude_none=True)
25
+
26
+ @mcp.tool()
27
+ def modify_architecture(spec_json: dict, instruction: str) -> dict:
28
+ """Modify an existing architecture with a natural language instruction."""
29
+ from cloudwright.architect import Architect
30
+ from cloudwright.spec import ArchSpec
31
+
32
+ spec = ArchSpec.model_validate(spec_json)
33
+ modified = Architect().modify(spec, instruction)
34
+ return modified.model_dump(exclude_none=True)
35
+
36
+ @mcp.tool()
37
+ def compare_providers(spec_json: dict, providers: list[str]) -> list[dict]:
38
+ """Compare an architecture across cloud providers."""
39
+ from cloudwright.architect import Architect
40
+ from cloudwright.spec import ArchSpec
41
+
42
+ spec = ArchSpec.model_validate(spec_json)
43
+ alternatives = Architect().compare(spec, providers)
44
+ return [a.model_dump(exclude_none=True) for a in alternatives]
@@ -0,0 +1,42 @@
1
+ from __future__ import annotations
2
+
3
+ from mcp.server.fastmcp import FastMCP
4
+
5
+
6
+ def register(mcp: FastMCP) -> None:
7
+ @mcp.tool()
8
+ def export_architecture(spec_json: dict, format: str = "terraform") -> dict:
9
+ """Export an architecture spec to Terraform, CloudFormation, Mermaid, D2, or other formats."""
10
+ from cloudwright.exporter import export_spec
11
+ from cloudwright.spec import ArchSpec
12
+
13
+ spec = ArchSpec.model_validate(spec_json)
14
+ content = export_spec(spec, fmt=format)
15
+ return {"format": format, "content": content}
16
+
17
+ @mcp.tool()
18
+ def list_services(provider: str = "aws") -> list[dict]:
19
+ """List all cloud services for a provider from the service registry."""
20
+ from cloudwright.registry import ServiceRegistry
21
+
22
+ services = ServiceRegistry().list_services(provider)
23
+ return [s.to_dict() for s in services]
24
+
25
+ @mcp.tool()
26
+ def catalog_search(
27
+ provider: str = "aws",
28
+ query: str | None = None,
29
+ vcpus: int | None = None,
30
+ memory_gb: float | None = None,
31
+ max_price_per_hour: float | None = None,
32
+ ) -> list[dict]:
33
+ """Search the cloud instance catalog by provider, specs, or text query."""
34
+ from cloudwright.catalog import Catalog
35
+
36
+ return Catalog().search(
37
+ query=query,
38
+ provider=provider,
39
+ vcpus=vcpus,
40
+ memory_gb=memory_gb,
41
+ max_price_per_hour=max_price_per_hour,
42
+ )
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ import uuid
4
+
5
+ from mcp.server.fastmcp import FastMCP
6
+
7
+ _sessions: dict[str, object] = {}
8
+
9
+
10
+ def register(mcp: FastMCP) -> None:
11
+ @mcp.tool()
12
+ def chat_create_session(
13
+ provider: str = "aws",
14
+ budget_monthly: float | None = None,
15
+ compliance: list[str] | None = None,
16
+ ) -> dict:
17
+ """Create a new stateful architecture design conversation session."""
18
+ from cloudwright.architect import ConversationSession
19
+ from cloudwright.spec import Constraints
20
+
21
+ constraints = Constraints(budget_monthly=budget_monthly, compliance=compliance or [])
22
+ session = ConversationSession(constraints=constraints)
23
+ session_id = uuid.uuid4().hex[:12]
24
+ _sessions[session_id] = session
25
+ return {"session_id": session_id}
26
+
27
+ @mcp.tool()
28
+ def chat_send(session_id: str, message: str) -> dict:
29
+ """Send a message to an existing conversation session and get a response."""
30
+ session = _sessions.get(session_id)
31
+ if session is None:
32
+ return {"error": f"Session {session_id!r} not found. Create one with chat_create_session."}
33
+
34
+ text, spec = session.send(message)
35
+ return {
36
+ "response": text,
37
+ "spec": spec.model_dump(exclude_none=True) if spec is not None else None,
38
+ }
39
+
40
+ @mcp.tool()
41
+ def chat_list_sessions() -> list[dict]:
42
+ """List all active conversation sessions."""
43
+ from cloudwright.architect import ConversationSession
44
+
45
+ result = []
46
+ for sid, session in _sessions.items():
47
+ if isinstance(session, ConversationSession):
48
+ result.append(
49
+ {
50
+ "session_id": sid,
51
+ "message_count": len(session.history),
52
+ "has_spec": session.current_spec is not None,
53
+ }
54
+ )
55
+ return result
@@ -0,0 +1,53 @@
1
+ from __future__ import annotations
2
+
3
+ from mcp.server.fastmcp import FastMCP
4
+
5
+
6
+ def register(mcp: FastMCP) -> None:
7
+ @mcp.tool()
8
+ def validate_compliance(
9
+ spec_json: dict,
10
+ frameworks: list[str],
11
+ well_architected: bool = False,
12
+ ) -> list[dict]:
13
+ """Validate an architecture against compliance frameworks."""
14
+ from cloudwright.spec import ArchSpec
15
+ from cloudwright.validator import Validator
16
+
17
+ spec = ArchSpec.model_validate(spec_json)
18
+ results = Validator().validate(spec, compliance=frameworks, well_architected=well_architected)
19
+ return [r.model_dump(exclude_none=True) for r in results]
20
+
21
+ @mcp.tool()
22
+ def security_scan(spec_json: dict) -> dict:
23
+ """Scan an architecture for security anti-patterns and misconfigurations."""
24
+ from cloudwright.security import SecurityScanner
25
+ from cloudwright.spec import ArchSpec
26
+
27
+ from cloudwright_mcp.serializers import security_report_to_dict
28
+
29
+ spec = ArchSpec.model_validate(spec_json)
30
+ report = SecurityScanner().scan(spec)
31
+ return security_report_to_dict(report)
32
+
33
+ @mcp.tool()
34
+ def scan_terraform(hcl_content: str) -> dict:
35
+ """Scan Terraform HCL for security misconfigurations."""
36
+ from cloudwright.security import scan_terraform as _scan_terraform
37
+
38
+ from cloudwright_mcp.serializers import security_report_to_dict
39
+
40
+ report = _scan_terraform(hcl_content)
41
+ return security_report_to_dict(report)
42
+
43
+ @mcp.tool()
44
+ def lint_architecture(spec_json: dict) -> list[dict]:
45
+ """Lint an architecture for anti-patterns and best-practice violations."""
46
+ from cloudwright.linter import lint
47
+ from cloudwright.spec import ArchSpec
48
+
49
+ from cloudwright_mcp.serializers import lint_warnings_to_dict
50
+
51
+ spec = ArchSpec.model_validate(spec_json)
52
+ warnings = lint(spec)
53
+ return lint_warnings_to_dict(warnings)