This is page 2 of 4. Use http://codebase.md/severity1/terraform-cloud-mcp?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .gitignore
├── .python-version
├── CLAUDE.md
├── docs
│ ├── API_REFERENCES.md
│ ├── CLAUDE.md
│ ├── CONTRIBUTING.md
│ ├── conversations
│ │ ├── account.md
│ │ ├── apply-management-conversation.md
│ │ ├── assessment-results-conversation.md
│ │ ├── cost-estimate-conversation.md
│ │ ├── organization-entitlements-conversation.md
│ │ ├── organizations-management-conversation.md
│ │ ├── plan-management-conversation.md
│ │ ├── project-management-conversation.md
│ │ ├── runs-management-conversation.md
│ │ ├── state_management.md
│ │ ├── variables-conversation.md
│ │ └── workspace-management-conversation.md
│ ├── DEVELOPMENT.md
│ ├── FILTERING_SYSTEM.md
│ ├── models
│ │ ├── account.md
│ │ ├── apply.md
│ │ ├── assessment_result.md
│ │ ├── cost_estimate.md
│ │ ├── organization.md
│ │ ├── plan.md
│ │ ├── project.md
│ │ ├── run.md
│ │ ├── state_version_outputs.md
│ │ ├── state_versions.md
│ │ ├── variables.md
│ │ └── workspace.md
│ ├── README.md
│ └── tools
│ ├── account.md
│ ├── apply.md
│ ├── assessment_results.md
│ ├── cost_estimate.md
│ ├── organization.md
│ ├── plan.md
│ ├── project.md
│ ├── run.md
│ ├── state_version_outputs.md
│ ├── state_versions.md
│ ├── variables.md
│ └── workspace.md
├── env.example
├── LICENSE
├── mypy.ini
├── pyproject.toml
├── README.md
├── terraform_cloud_mcp
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── CLAUDE.md
│ │ └── client.py
│ ├── configs
│ │ ├── __init__.py
│ │ ├── CLAUDE.md
│ │ └── filter_configs.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── account.py
│ │ ├── applies.py
│ │ ├── assessment_results.py
│ │ ├── base.py
│ │ ├── CLAUDE.md
│ │ ├── cost_estimates.py
│ │ ├── filters.py
│ │ ├── organizations.py
│ │ ├── plans.py
│ │ ├── projects.py
│ │ ├── runs.py
│ │ ├── state_version_outputs.py
│ │ ├── state_versions.py
│ │ ├── variables.py
│ │ └── workspaces.py
│ ├── server.py
│ ├── tools
│ │ ├── __init__.py
│ │ ├── account.py
│ │ ├── applies.py
│ │ ├── assessment_results.py
│ │ ├── CLAUDE.md
│ │ ├── cost_estimates.py
│ │ ├── organizations.py
│ │ ├── plans.py
│ │ ├── projects.py
│ │ ├── runs.py
│ │ ├── state_version_outputs.py
│ │ ├── state_versions.py
│ │ ├── variables.py
│ │ └── workspaces.py
│ └── utils
│ ├── __init__.py
│ ├── CLAUDE.md
│ ├── decorators.py
│ ├── env.py
│ ├── filters.py
│ ├── payload.py
│ └── request.py
└── uv.lock
```
# Files
--------------------------------------------------------------------------------
/docs/models/state_versions.md:
--------------------------------------------------------------------------------
```markdown
1 | # State Version Models
2 |
3 | This document describes the data models used for state version operations in Terraform Cloud.
4 |
5 | ## Overview
6 |
7 | State version models provide structure and validation for interacting with the Terraform Cloud State Versions API. These models define the format of state version data, status values, and request validation for managing point-in-time snapshots of Terraform state files.
8 |
9 | ## Models Reference
10 |
11 | ### StateVersionStatus
12 |
13 | **Type:** Enum (string)
14 |
15 | **Description:** Represents the possible states a state version can be in during its lifecycle.
16 |
17 | **Values:**
18 | - `pending`: State version has been created but the state data is not encoded within the request
19 | - `finalized`: State version has been successfully uploaded or created with valid state attribute
20 | - `discarded`: State version was discarded because it was superseded by a newer state version
21 | - `backing_data_soft_deleted`: *Enterprise only* - backing files are marked for garbage collection
22 | - `backing_data_permanently_deleted`: *Enterprise only* - backing files have been permanently deleted
23 |
24 | **Usage Context:**
25 | Used to filter state versions by their current status and determine if processing is complete.
26 |
27 | ### StateVersionListRequest
28 |
29 | **Type:** Request Validation Model
30 |
31 | **Description:** Used to validate parameters for listing state versions in a workspace.
32 |
33 | **Fields:**
34 | - `workspace_name` (string, required): The name of the workspace to list state versions for
35 | - `organization` (string, required): The name of the organization that owns the workspace
36 | - `filter_status` (StateVersionStatus, optional): Filter state versions by status
37 | - `page_number` (integer, optional): Page number to fetch (default: 1, minimum: 1)
38 | - `page_size` (integer, optional): Number of results per page (default: 20, max: 100)
39 |
40 | ### StateVersionRequest
41 |
42 | **Type:** Request Validation Model
43 |
44 | **Description:** Used to validate state version ID parameters in API requests.
45 |
46 | **Fields:**
47 | - `state_version_id` (string, required): The ID of the state version to retrieve
48 | - Format: Must match pattern "sv-[a-zA-Z0-9]{16}"
49 | - Example: "sv-BPvFFrYCqRV6qVBK"
50 |
51 | ### CurrentStateVersionRequest
52 |
53 | **Type:** Request Validation Model
54 |
55 | **Description:** Used to validate workspace ID parameters for current state version requests.
56 |
57 | **Fields:**
58 | - `workspace_id` (string, required): The ID of the workspace
59 | - Format: Must match pattern "ws-[a-zA-Z0-9]{16}"
60 | - Example: "ws-BPvFFrYCqRV6qVBK"
61 |
62 | ### StateVersionCreateRequest
63 |
64 | **Type:** Request Validation Model
65 |
66 | **Description:** Used to validate parameters for creating new state versions.
67 |
68 | **Fields:**
69 | - `workspace_id` (string, required): The ID of the workspace to create the state version in
70 | - `serial` (integer, required): The serial number of this state instance (minimum: 0)
71 | - `md5` (string, required): An MD5 hash of the raw state version (32 character hex string)
72 | - `state` (string, optional): Base64 encoded raw state file
73 | - `lineage` (string, optional): Lineage of the state version
74 | - `json_state` (string, optional): Base64 encoded JSON state from "terraform show -json"
75 | - `json_state_outputs` (string, optional): Base64 encoded JSON state outputs
76 | - `run_id` (string, optional): The ID of the run to associate with the state version
77 |
78 | ### StateVersionParams
79 |
80 | **Type:** Parameter Object
81 |
82 | **Description:** Flexible parameter model for state version operations without routing fields.
83 |
84 | **Fields:**
85 | All fields from StateVersionCreateRequest excluding workspace_id, with all fields optional.
86 |
87 | **JSON representation:**
88 | ```json
89 | {
90 | "serial": 1,
91 | "md5": "d41d8cd98f00b204e9800998ecf8427e",
92 | "lineage": "871d1b4a-e579-fb7c-ffdb-f0c858a647a7",
93 | "json-state": "H4sIAAAA...",
94 | "json-state-outputs": "H4sIAAAA..."
95 | }
96 | ```
97 |
98 | **Notes:**
99 | - Field names in JSON responses use kebab-case format (e.g., "json-state")
100 | - Field names in the model use snake_case format (e.g., json_state)
101 | - All encoded fields expect Base64 format
102 |
103 | ## API Response Structure
104 |
105 | While models validate requests, responses are returned as raw JSON. A typical state version response has this structure:
106 |
107 | ```json
108 | {
109 | "data": {
110 | "id": "sv-BPvFFrYCqRV6qVBK",
111 | "type": "state-versions",
112 | "attributes": {
113 | "created-at": "2023-05-01T12:34:56Z",
114 | "size": 1024,
115 | "hosted-state-download-url": "https://...",
116 | "hosted-json-state-download-url": "https://...",
117 | "modules": {...},
118 | "providers": {...},
119 | "resources": [...],
120 | "serial": 1,
121 | "state-version": 4,
122 | "terraform-version": "1.5.0",
123 | "vcs-commit-sha": "abc123",
124 | "vcs-commit-url": "https://..."
125 | },
126 | "relationships": {
127 | "run": {...},
128 | "created-by": {...}
129 | }
130 | }
131 | }
132 | ```
133 |
134 | ## Related Resources
135 |
136 | - [State Version Tools](../tools/state_versions.md)
137 | - [State Version Outputs Models](./state_version_outputs.md)
138 | - [Terraform Cloud API - State Versions](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions)
```
--------------------------------------------------------------------------------
/terraform_cloud_mcp/tools/assessment_results.py:
--------------------------------------------------------------------------------
```python
1 | """Terraform Cloud assessment results management tools.
2 |
3 | This module provides tools for working with health assessment results in Terraform Cloud.
4 | It includes functions to retrieve assessment details, JSON output, schema files, and logs.
5 |
6 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/assessment-results
7 | """
8 |
9 | from ..api.client import api_request
10 | from ..models.base import APIResponse
11 | from ..models.assessment_results import AssessmentResultRequest, AssessmentOutputRequest
12 | from ..utils.decorators import handle_api_errors
13 |
14 |
15 | @handle_api_errors
16 | async def get_assessment_result_details(assessment_result_id: str) -> APIResponse:
17 | """Get details for a specific assessment result.
18 |
19 | Retrieves comprehensive information about an assessment result including its current status,
20 | whether drift was detected, and links to related resources like JSON output and logs.
21 |
22 | API endpoint: GET /api/v2/assessment-results/{assessment_result_id}
23 |
24 | Args:
25 | assessment_result_id: The ID of the assessment result to retrieve details for (format: "asmtres-xxxxxxxx")
26 |
27 | Returns:
28 | Assessment result details including status, timestamps, and drift detection information
29 |
30 | See:
31 | docs/tools/assessment_results.md for reference documentation
32 | """
33 | # Validate parameters
34 | params = AssessmentResultRequest(assessment_result_id=assessment_result_id)
35 |
36 | # Make API request
37 | return await api_request(f"assessment-results/{params.assessment_result_id}")
38 |
39 |
40 | @handle_api_errors
41 | async def get_assessment_json_output(assessment_result_id: str) -> APIResponse:
42 | """Retrieve the JSON execution plan from an assessment result.
43 |
44 | Gets the JSON representation of the plan execution details from an assessment,
45 | providing a machine-readable format of the planned resource changes.
46 |
47 | API endpoint: GET /api/v2/assessment-results/{assessment_result_id}/json-output
48 |
49 | Args:
50 | assessment_result_id: The ID of the assessment result to retrieve JSON output for (format: "asmtres-xxxxxxxx")
51 |
52 | Returns:
53 | The complete JSON formatted plan with resource changes, metadata,
54 | and planned actions. The redirect is automatically followed.
55 |
56 | Note:
57 | This endpoint requires admin level access to the workspace and cannot be accessed
58 | with organization tokens.
59 |
60 | See:
61 | docs/tools/assessment_results.md for reference documentation
62 | """
63 | # Validate parameters
64 | params = AssessmentOutputRequest(assessment_result_id=assessment_result_id)
65 |
66 | # Make API request with text acceptance since it may be a large JSON file
67 | return await api_request(
68 | f"assessment-results/{params.assessment_result_id}/json-output",
69 | accept_text=True,
70 | )
71 |
72 |
73 | @handle_api_errors
74 | async def get_assessment_json_schema(assessment_result_id: str) -> APIResponse:
75 | """Retrieve the JSON schema file from an assessment result.
76 |
77 | Gets the JSON schema representation of the provider schema used during the assessment,
78 | providing information about available resources and their configuration options.
79 |
80 | API endpoint: GET /api/v2/assessment-results/{assessment_result_id}/json-schema
81 |
82 | Args:
83 | assessment_result_id: The ID of the assessment result to retrieve schema for (format: "asmtres-xxxxxxxx")
84 |
85 | Returns:
86 | The JSON schema file containing provider information. The redirect is automatically followed.
87 |
88 | Note:
89 | This endpoint requires admin level access to the workspace and cannot be accessed
90 | with organization tokens.
91 |
92 | See:
93 | docs/tools/assessment_results.md for reference documentation
94 | """
95 | # Validate parameters
96 | params = AssessmentOutputRequest(assessment_result_id=assessment_result_id)
97 |
98 | # Make API request with text acceptance since it may be a large JSON file
99 | return await api_request(
100 | f"assessment-results/{params.assessment_result_id}/json-schema",
101 | accept_text=True,
102 | )
103 |
104 |
105 | @handle_api_errors
106 | async def get_assessment_log_output(assessment_result_id: str) -> APIResponse:
107 | """Retrieve logs from an assessment result.
108 |
109 | Gets the raw log output from a Terraform Cloud assessment operation,
110 | providing detailed information about the execution and any errors.
111 |
112 | API endpoint: GET /api/v2/assessment-results/{assessment_result_id}/log-output
113 |
114 | Args:
115 | assessment_result_id: The ID of the assessment result to retrieve logs for (format: "asmtres-xxxxxxxx")
116 |
117 | Returns:
118 | The raw logs from the assessment operation. The redirect to the log file
119 | is automatically followed.
120 |
121 | Note:
122 | This endpoint requires admin level access to the workspace and cannot be accessed
123 | with organization tokens.
124 |
125 | See:
126 | docs/tools/assessment_results.md for reference documentation
127 | """
128 | # Validate parameters
129 | params = AssessmentOutputRequest(assessment_result_id=assessment_result_id)
130 |
131 | # Make API request with text acceptance for the logs
132 | return await api_request(
133 | f"assessment-results/{params.assessment_result_id}/log-output", accept_text=True
134 | )
135 |
```
--------------------------------------------------------------------------------
/docs/tools/state_versions.md:
--------------------------------------------------------------------------------
```markdown
1 | # State Version Tools
2 |
3 | The state version tools module provides functions for working with state versions in Terraform Cloud.
4 |
5 | ## Overview
6 |
7 | State versions represent point-in-time snapshots of Terraform state files. These tools allow you to manage the complete lifecycle of state versions, including listing, retrieving, creating, and downloading state data. This is particularly useful for state migration and workspace management.
8 |
9 | ## API Reference
10 |
11 | These tools interact with the Terraform Cloud State Versions API:
12 | - [State Versions API Documentation](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions)
13 | - [State Versions Concepts](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/state)
14 |
15 | ## Tools Reference
16 |
17 | ### list_state_versions
18 |
19 | **Function:** `list_state_versions(organization: str, workspace_name: str, page_number: int = 1, page_size: int = 20, filter_status: Optional[str] = None) -> Dict[str, Any]`
20 |
21 | **Description:** Retrieves a paginated list of state versions for a workspace with optional status filtering.
22 |
23 | **Parameters:**
24 | - `organization` (str): The organization name
25 | - `workspace_name` (str): The workspace name
26 | - `page_number` (int): Page number to fetch (default: 1)
27 | - `page_size` (int): Number of results per page (default: 20, max: 100)
28 | - `filter_status` (str): Filter by status: 'pending', 'finalized', or 'discarded'
29 |
30 | **Returns:** JSON response containing paginated state versions with metadata including serial numbers, creation timestamps, and download URLs.
31 |
32 | **Notes:**
33 | - State versions are ordered by creation date (newest first)
34 | - The `resources-processed` attribute indicates if asynchronous processing is complete
35 | - Requires "read" permission for the workspace
36 |
37 | ### get_current_state_version
38 |
39 | **Function:** `get_current_state_version(workspace_id: str) -> Dict[str, Any]`
40 |
41 | **Description:** Retrieves the current active state version for a workspace.
42 |
43 | **Parameters:**
44 | - `workspace_id` (str): The ID of the workspace (format: "ws-xxxxxxxx")
45 |
46 | **Returns:** JSON response containing the current state version details including download URLs and metadata.
47 |
48 | **Notes:**
49 | - Returns the state version that serves as input for new runs
50 | - May return empty if no state versions exist for the workspace
51 | - Requires "read" permission for the workspace
52 |
53 | ### get_state_version
54 |
55 | **Function:** `get_state_version(state_version_id: str) -> Dict[str, Any]`
56 |
57 | **Description:** Retrieves detailed information about a specific state version by ID.
58 |
59 | **Parameters:**
60 | - `state_version_id` (str): The ID of the state version (format: "sv-xxxxxxxx")
61 |
62 | **Returns:** JSON response containing comprehensive state version details including resources, modules, providers, and download URLs.
63 |
64 | **Notes:**
65 | - Includes detailed resource and module information if processing is complete
66 | - Contains both raw state and JSON state download URLs (when available)
67 | - Requires "read" permission for the associated workspace
68 |
69 | ### create_state_version
70 |
71 | **Function:** `create_state_version(workspace_id: str, serial: int, md5: str, params: Optional[StateVersionParams] = None) -> Dict[str, Any]`
72 |
73 | **Description:** Creates a new state version in a workspace, useful for migrating state from Terraform Community Edition.
74 |
75 | **Parameters:**
76 | - `workspace_id` (str): The ID of the workspace (format: "ws-xxxxxxxx")
77 | - `serial` (int): The serial number of this state instance
78 | - `md5` (str): An MD5 hash of the raw state version
79 | - `params` (StateVersionParams): Additional configuration including state data and lineage
80 |
81 | **Returns:** JSON response containing the created state version with upload URLs if state data wasn't provided.
82 |
83 | **Notes:**
84 | - Workspace must be locked by the user creating the state version
85 | - Can provide state data directly or use returned upload URLs
86 | - Requires "write" permission for the workspace
87 |
88 | ### download_state_file
89 |
90 | **Function:** `download_state_file(state_version_id: str, json_format: bool = False) -> Dict[str, Any]`
91 |
92 | **Description:** Downloads the raw state file content or JSON formatted state for a specific state version.
93 |
94 | **Parameters:**
95 | - `state_version_id` (str): The ID of the state version (format: "sv-xxxxxxxx")
96 | - `json_format` (bool): Whether to download JSON formatted state (default: False)
97 |
98 | **Returns:** Raw state file content or JSON formatted state content.
99 |
100 | **Notes:**
101 | - JSON format requires Terraform 1.3+ to be available
102 | - Raw format returns the actual Terraform state file
103 | - Requires "read" permission for the associated workspace
104 |
105 | **Common Error Scenarios:**
106 |
107 | | Error | Cause | Solution |
108 | |-------|-------|----------|
109 | | 404 | State version not found | Verify the ID exists and you have proper permissions |
110 | | 422 | Invalid state version ID format | Ensure the ID matches pattern "sv-xxxxxxxx" |
111 | | 403 | Insufficient permissions | Verify your API token has proper workspace access |
112 | | 409 | Workspace not locked (create only) | Lock the workspace before creating state versions |
113 |
114 | ## Related Resources
115 |
116 | - [State Version Models](../models/state_versions.md)
117 | - [State Version Outputs Tools](./state_version_outputs.md)
118 | - [Terraform Cloud API - State Versions](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions)
```
--------------------------------------------------------------------------------
/docs/models/plan.md:
--------------------------------------------------------------------------------
```markdown
1 | # Plan Models
2 |
3 | This document describes the data models used for plan operations in Terraform Cloud.
4 |
5 | ## Overview
6 |
7 | Plan models provide structure and validation for interacting with the Terraform Cloud Plans API. These models define plan statuses, execution details, and request validation for retrieving plan information.
8 |
9 | ## Models Reference
10 |
11 | ### PlanStatus
12 |
13 | **Type:** Enum (string)
14 |
15 | **Description:** Represents the possible states a plan can be in during its lifecycle.
16 |
17 | **Values:**
18 | - `pending`: Plan has not yet started
19 | - `managed_queued`: Plan is waiting for other runs in the queue
20 | - `queued`: Plan is queued for execution
21 | - `running`: Plan is currently executing
22 | - `errored`: Plan encountered an error
23 | - `canceled`: Plan was canceled
24 | - `finished`: Plan completed successfully
25 |
26 | **Usage Context:**
27 | Used to determine the current state of a plan and whether it has completed successfully.
28 |
29 | ### ExecutionDetails
30 |
31 | **Type:** Object
32 |
33 | **Description:** Contains information about how a plan was executed, particularly for agent-based execution.
34 |
35 | **Fields:**
36 | - `agent_id` (string, optional): ID of the agent that executed the plan
37 | - `agent_name` (string, optional): Name of the agent that executed the plan
38 | - `agent_pool_id` (string, optional): ID of the agent pool the executing agent belongs to
39 | - `agent_pool_name` (string, optional): Name of the agent pool the executing agent belongs to
40 |
41 | **JSON representation:**
42 | ```json
43 | {
44 | "execution-details": {
45 | "agent-id": "agent-AbCdEfGhIjKlMnOp",
46 | "agent-name": "production-agent-01",
47 | "agent-pool-id": "apool-AbCdEfGhIjKlMnOp",
48 | "agent-pool-name": "Production Agents"
49 | }
50 | }
51 | ```
52 |
53 | ### StatusTimestamps
54 |
55 | **Type:** Object
56 |
57 | **Description:** Captures timing information for various stages in a plan's lifecycle.
58 |
59 | **Fields:**
60 | - `queued_at` (string, optional): ISO8601 timestamp when the plan was queued
61 | - `pending_at` (string, optional): ISO8601 timestamp when the plan was pending
62 | - `started_at` (string, optional): ISO8601 timestamp when plan execution started
63 | - `finished_at` (string, optional): ISO8601 timestamp when plan execution completed
64 |
65 | **JSON representation:**
66 | ```json
67 | {
68 | "status-timestamps": {
69 | "queued-at": "2023-09-01T12:00:00Z",
70 | "pending-at": "2023-09-01T12:01:00Z",
71 | "started-at": "2023-09-01T12:02:00Z",
72 | "finished-at": "2023-09-01T12:10:00Z"
73 | }
74 | }
75 | ```
76 |
77 | **Notes:**
78 | - Field names in JSON responses use kebab-case format (e.g., "queued-at")
79 | - Field names in the model use snake_case format (e.g., queued_at)
80 | - All timestamp fields follow ISO8601 format
81 |
82 | ### PlanRequest
83 |
84 | **Type:** Request Validation Model
85 |
86 | **Description:** Used to validate plan ID parameters in API requests.
87 |
88 | **Fields:**
89 | - `plan_id` (string, required): The ID of the plan to retrieve
90 | - Format: Must match pattern "plan-[a-zA-Z0-9]{16}"
91 | - Example: "plan-AbCdEfGhIjKlMnOp"
92 |
93 | **Validation Rules:**
94 | - Plan ID must start with "plan-" prefix
95 | - Must contain exactly 16 alphanumeric characters after the prefix
96 |
97 | ### PlanJsonOutputRequest
98 |
99 | **Type:** Request Validation Model
100 |
101 | **Description:** Used to validate parameters for retrieving the JSON output of a plan.
102 |
103 | **Fields:**
104 | - `plan_id` (string, required): The ID of the plan to retrieve JSON output for
105 | - Format: Must match pattern "plan-[a-zA-Z0-9]{16}"
106 | - Example: "plan-AbCdEfGhIjKlMnOp"
107 |
108 | ### RunPlanJsonOutputRequest
109 |
110 | **Type:** Request Validation Model
111 |
112 | **Description:** Used to validate parameters for retrieving the JSON output of a run's plan.
113 |
114 | **Fields:**
115 | - `run_id` (string, required): The ID of the run to retrieve plan JSON output for
116 | - Format: Must match pattern "run-[a-zA-Z0-9]{16}"
117 | - Example: "run-AbCdEfGhIjKlMnOp"
118 |
119 | ## API Response Structure
120 |
121 | ### Plan Details Response
122 |
123 | ```json
124 | {
125 | "data": {
126 | "id": "plan-AbCdEfGhIjKlMnOp",
127 | "type": "plans",
128 | "attributes": {
129 | "status": "finished",
130 | "status-timestamps": {
131 | "queued-at": "2023-09-01T12:00:00Z",
132 | "pending-at": "2023-09-01T12:01:00Z",
133 | "started-at": "2023-09-01T12:02:00Z",
134 | "finished-at": "2023-09-01T12:10:00Z"
135 | },
136 | "resource-additions": 3,
137 | "resource-changes": 2,
138 | "resource-destructions": 1,
139 | "execution-details": {
140 | "agent-id": "agent-AbCdEfGhIjKlMnOp",
141 | "agent-name": "production-agent-01",
142 | "agent-pool-id": "apool-AbCdEfGhIjKlMnOp",
143 | "agent-pool-name": "Production Agents"
144 | }
145 | },
146 | "relationships": {
147 | "run": {
148 | "data": {
149 | "id": "run-AbCdEfGhIjKlMnOp",
150 | "type": "runs"
151 | }
152 | },
153 | "state-versions": {
154 | "data": {
155 | "id": "sv-AbCdEfGhIjKlMnOp",
156 | "type": "state-versions"
157 | }
158 | }
159 | },
160 | "links": {
161 | "self": "/api/v2/plans/plan-AbCdEfGhIjKlMnOp",
162 | "json-output": "/api/v2/plans/plan-AbCdEfGhIjKlMnOp/json-output"
163 | }
164 | }
165 | }
166 | ```
167 |
168 | ### Plan JSON Output Response
169 |
170 | The plan JSON output response contains a string in the `data` field that can be parsed to access detailed information about the planned resource changes:
171 |
172 | ```json
173 | {
174 | "data": "<JSON string containing the full plan details>"
175 | }
176 | ```
177 |
178 | The parsed plan data includes information about:
179 | - Resource additions, changes, and deletions
180 | - Output changes
181 | - Provider configurations
182 | - Prior state details
183 | - Terraform version information
184 |
185 | ## Related Resources
186 |
187 | - [Plan Tools](../tools/plan.md)
188 | - [Run Models](run.md)
189 | - [Terraform Cloud API - Plans](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/plans)
```
--------------------------------------------------------------------------------
/terraform_cloud_mcp/server.py:
--------------------------------------------------------------------------------
```python
1 | #!/usr/bin/env python3
2 | """
3 | Terraform Cloud MCP Server
4 | """
5 |
6 | import logging
7 | from fastmcp import FastMCP
8 |
9 | # Import environment configuration
10 | from terraform_cloud_mcp.utils.env import should_enable_delete_tools
11 |
12 | # Import tools and models
13 | from terraform_cloud_mcp.tools import account
14 | from terraform_cloud_mcp.tools import workspaces
15 | from terraform_cloud_mcp.tools import runs
16 | from terraform_cloud_mcp.tools import organizations
17 | from terraform_cloud_mcp.tools import plans
18 | from terraform_cloud_mcp.tools import applies
19 | from terraform_cloud_mcp.tools import projects
20 | from terraform_cloud_mcp.tools import cost_estimates
21 | from terraform_cloud_mcp.tools import assessment_results
22 | from terraform_cloud_mcp.tools import state_versions
23 | from terraform_cloud_mcp.tools import state_version_outputs
24 | from terraform_cloud_mcp.tools import variables
25 |
26 | # Configure logging
27 | logging.basicConfig(level=logging.DEBUG)
28 |
29 | # Create server instance
30 | mcp: FastMCP = FastMCP("Terraform Cloud MCP Server")
31 |
32 | # Check if delete tools should be enabled
33 | enable_delete_tools = should_enable_delete_tools()
34 |
35 | # Register account management tools
36 | mcp.tool()(account.get_account_details)
37 |
38 | # Register workspace management tools
39 | mcp.tool()(workspaces.list_workspaces)
40 | mcp.tool()(workspaces.get_workspace_details)
41 | mcp.tool()(workspaces.create_workspace)
42 | mcp.tool()(workspaces.update_workspace)
43 | mcp.tool(
44 | enabled=enable_delete_tools,
45 | annotations={"destructiveHint": True, "readOnlyHint": False},
46 | )(workspaces.delete_workspace)
47 | mcp.tool(
48 | enabled=enable_delete_tools,
49 | annotations={"destructiveHint": True, "readOnlyHint": False},
50 | )(workspaces.safe_delete_workspace)
51 | mcp.tool()(workspaces.lock_workspace)
52 | mcp.tool()(workspaces.unlock_workspace)
53 | mcp.tool()(workspaces.force_unlock_workspace)
54 |
55 | # Register run management tools
56 | mcp.tool()(runs.create_run)
57 | mcp.tool()(runs.list_runs_in_workspace)
58 | mcp.tool()(runs.list_runs_in_organization)
59 | mcp.tool()(runs.get_run_details)
60 | mcp.tool()(runs.apply_run)
61 | mcp.tool()(runs.discard_run)
62 | mcp.tool()(runs.cancel_run)
63 | mcp.tool()(runs.force_cancel_run)
64 | mcp.tool()(runs.force_execute_run)
65 |
66 | # Register organization management tools
67 | mcp.tool()(organizations.get_organization_details)
68 | mcp.tool()(organizations.get_organization_entitlements)
69 | mcp.tool()(organizations.list_organizations)
70 | mcp.tool()(organizations.create_organization)
71 | mcp.tool()(organizations.update_organization)
72 | mcp.tool(
73 | enabled=enable_delete_tools,
74 | annotations={"destructiveHint": True, "readOnlyHint": False},
75 | )(organizations.delete_organization)
76 |
77 | # Register plan management tools
78 | mcp.tool()(plans.get_plan_details)
79 | mcp.tool()(plans.get_plan_json_output)
80 | mcp.tool()(plans.get_run_plan_json_output)
81 | mcp.tool()(plans.get_plan_logs)
82 |
83 | # Register apply management tools
84 | mcp.tool()(applies.get_apply_details)
85 | mcp.tool()(applies.get_errored_state)
86 | mcp.tool()(applies.get_apply_logs)
87 |
88 | # Register project management tools
89 | mcp.tool()(projects.create_project)
90 | mcp.tool()(projects.update_project)
91 | mcp.tool()(projects.list_projects)
92 | mcp.tool()(projects.get_project_details)
93 | mcp.tool(
94 | enabled=enable_delete_tools,
95 | annotations={"destructiveHint": True, "readOnlyHint": False},
96 | )(projects.delete_project)
97 | mcp.tool()(projects.list_project_tag_bindings)
98 | mcp.tool()(projects.add_update_project_tag_bindings)
99 | mcp.tool()(projects.move_workspaces_to_project)
100 |
101 | # Register cost estimates tools
102 | mcp.tool()(cost_estimates.get_cost_estimate_details)
103 |
104 | # Register assessment results tools
105 | mcp.tool()(assessment_results.get_assessment_result_details)
106 | mcp.tool()(assessment_results.get_assessment_json_output)
107 | mcp.tool()(assessment_results.get_assessment_json_schema)
108 | mcp.tool()(assessment_results.get_assessment_log_output)
109 |
110 | # Register state version tools
111 | mcp.tool()(state_versions.list_state_versions)
112 | mcp.tool()(state_versions.get_current_state_version)
113 | mcp.tool()(state_versions.get_state_version)
114 | mcp.tool()(state_versions.create_state_version)
115 | mcp.tool()(state_versions.download_state_file)
116 |
117 | # Register state version outputs tools
118 | mcp.tool()(state_version_outputs.list_state_version_outputs)
119 | mcp.tool()(state_version_outputs.get_state_version_output)
120 |
121 | # Register variable management tools
122 | # Workspace Variables
123 | mcp.tool()(variables.list_workspace_variables)
124 | mcp.tool()(variables.create_workspace_variable)
125 | mcp.tool()(variables.update_workspace_variable)
126 | mcp.tool(
127 | enabled=enable_delete_tools,
128 | annotations={"destructiveHint": True, "readOnlyHint": False},
129 | )(variables.delete_workspace_variable)
130 |
131 | # Variable Sets
132 | mcp.tool()(variables.list_variable_sets)
133 | mcp.tool()(variables.get_variable_set)
134 | mcp.tool()(variables.create_variable_set)
135 | mcp.tool()(variables.update_variable_set)
136 | mcp.tool(
137 | enabled=enable_delete_tools,
138 | annotations={"destructiveHint": True, "readOnlyHint": False},
139 | )(variables.delete_variable_set)
140 | mcp.tool()(variables.assign_variable_set_to_workspaces)
141 | mcp.tool()(variables.unassign_variable_set_from_workspaces)
142 | mcp.tool()(variables.assign_variable_set_to_projects)
143 | mcp.tool()(variables.unassign_variable_set_from_projects)
144 |
145 | # Variable Set Variables
146 | mcp.tool()(variables.list_variables_in_variable_set)
147 | mcp.tool()(variables.create_variable_in_variable_set)
148 | mcp.tool()(variables.update_variable_in_variable_set)
149 | mcp.tool(
150 | enabled=enable_delete_tools,
151 | annotations={"destructiveHint": True, "readOnlyHint": False},
152 | )(variables.delete_variable_from_variable_set)
153 |
154 |
155 | def main() -> None:
156 | """Run the Terraform Cloud MCP server."""
157 |
158 | mcp.run(transport="stdio")
159 |
160 |
161 | if __name__ == "__main__":
162 | main()
163 |
```
--------------------------------------------------------------------------------
/docs/tools/organization.md:
--------------------------------------------------------------------------------
```markdown
1 | # Organization Tools
2 |
3 | This module provides tools for managing organizations in Terraform Cloud.
4 |
5 | ## Overview
6 |
7 | Organizations in Terraform Cloud are the top-level resource that represents a group or company. Organizations contain workspaces, teams, and other shared settings. These tools allow you to create, read, update, delete organizations, and view organization entitlements.
8 |
9 | ## API Reference
10 |
11 | These tools interact with the Terraform Cloud Organizations API:
12 | - [Organizations API Documentation](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations)
13 | - [Organizations and Teams](https://developer.hashicorp.com/terraform/cloud-docs/users-teams-organizations/organizations)
14 |
15 | ## Tools Reference
16 |
17 | ### list_organizations
18 |
19 | **Function:** `list_organizations(page_number: int = 1, page_size: int = 20, q: Optional[str] = None, query_email: Optional[str] = None, query_name: Optional[str] = None) -> Dict[str, Any]`
20 |
21 | **Description:** Retrieves a paginated list of organizations the current user has access to.
22 |
23 | **Parameters:**
24 | - `page_number` (int, optional): Page number to fetch (default: 1)
25 | - `page_size` (int, optional): Number of results per page (default: 20)
26 | - `q` (str, optional): Search query to filter by name and email
27 | - `query_email` (str, optional): Search query to filter by email only
28 | - `query_name` (str, optional): Search query to filter by name only
29 |
30 | **Returns:** JSON response containing list of organizations with their metadata.
31 |
32 | **Notes:**
33 | - Returns only organizations the authenticated user has access to
34 | - Search filters are partial matches (substrings)
35 | - Response is paginated with links to next/previous pages
36 |
37 | ### get_organization_details
38 |
39 | **Function:** `get_organization_details(organization: str) -> Dict[str, Any]`
40 |
41 | **Description:** Retrieves comprehensive information about a specific organization.
42 |
43 | **Parameters:**
44 | - `organization` (str): The name of the organization to retrieve details for
45 |
46 | **Returns:** JSON response containing detailed organization information including:
47 | - Name, email, and creation timestamp
48 | - Authentication policy settings
49 | - Default execution mode
50 | - Subscription and feature settings
51 |
52 | **Notes:**
53 | - Requires read access to the organization
54 | - Provides essential information before working with organization resources
55 |
56 | ### get_organization_entitlements
57 |
58 | **Function:** `get_organization_entitlements(organization: str) -> Dict[str, Any]`
59 |
60 | **Description:** Retrieves information about available features based on the organization's subscription tier.
61 |
62 | **Parameters:**
63 | - `organization` (str): The name of the organization to retrieve entitlements for
64 |
65 | **Returns:** JSON response containing feature limits and subscription information:
66 | - Available features (e.g., cost estimation, policy enforcement)
67 | - Resource limits (e.g., teams, private modules)
68 | - Subscription tier information
69 |
70 | **Notes:**
71 | - Essential for determining which features are available to an organization
72 | - Useful before attempting to use premium features
73 | - Different subscription tiers have different feature sets
74 |
75 | ### create_organization
76 |
77 | **Function:** `create_organization(name: str, email: str, params: Optional[OrganizationParams] = None) -> Dict[str, Any]`
78 |
79 | **Description:** Creates a new organization with the specified name and email.
80 |
81 | **Parameters:**
82 | - `name` (str): The name for the organization (must follow naming rules)
83 | - `email` (str): Email address for the admin contact
84 | - `params` (OrganizationParams, optional): Additional configuration settings:
85 | - `collaborator_auth_policy`: Authentication policy (password or two_factor_mandatory)
86 | - `session_timeout`: Session timeout after inactivity in minutes
87 | - `cost_estimation_enabled`: Whether to enable cost estimation
88 | - `default_execution_mode`: Default workspace execution mode
89 | - And many other options...
90 |
91 | **Returns:** JSON response with the created organization details.
92 |
93 | **Notes:**
94 | - Organization names must follow format constraints (lowercase alphanumeric, hyphens)
95 | - Names must be globally unique across Terraform Cloud
96 | - Only certain users have permission to create organizations
97 |
98 | ### update_organization
99 |
100 | **Function:** `update_organization(organization: str, params: Optional[OrganizationParams] = None) -> Dict[str, Any]`
101 |
102 | **Description:** Updates an existing organization's settings.
103 |
104 | **Parameters:**
105 | - `organization` (str): The name of the organization to update
106 | - `params` (OrganizationParams, optional): Settings to update:
107 | - `email`: Admin email address
108 | - `session_timeout`: Session timeout after inactivity
109 | - `collaborator_auth_policy`: Authentication policy
110 | - And all other options available in create_organization...
111 |
112 | **Returns:** JSON response with the updated organization details.
113 |
114 | **Notes:**
115 | - Only specified attributes will be updated
116 | - Requires admin permissions on the organization
117 | - Cannot change the organization name (immutable)
118 |
119 | ### delete_organization
120 |
121 | **Function:** `delete_organization(organization: str) -> Dict[str, Any]`
122 |
123 | **Description:** Permanently deletes an organization and all its content.
124 |
125 | **Parameters:**
126 | - `organization` (str): The name of the organization to delete
127 |
128 | **Returns:** Success confirmation (HTTP 204 No Content) or error details.
129 |
130 | **Notes:**
131 | - This is an extremely destructive operation
132 | - Will delete all workspaces, teams, configurations, and state files
133 | - Organization names cannot be recreated after deletion
134 | - Requires owner permissions
135 |
136 | **Common Error Scenarios:**
137 |
138 | | Error | Cause | Solution |
139 | |-------|-------|----------|
140 | | 404 | Organization not found | Verify the organization name |
141 | | 403 | Insufficient permissions | Must be an organization owner to delete |
142 | | 422 | Validation failure | Ensure the name format is correct |
143 | | 409 | Organization has child resources | Delete all child resources first |
```
--------------------------------------------------------------------------------
/docs/conversations/state_management.md:
--------------------------------------------------------------------------------
```markdown
1 | # State Management Conversation Example
2 |
3 | This document demonstrates how to use the State Management tools in Terraform Cloud MCP.
4 |
5 | ## Scenario: Working with State Versions and Their Outputs
6 |
7 | In this scenario, we'll show how to:
8 | 1. List state versions for a workspace
9 | 2. Get details of the current state version
10 | 3. Extract output values from the state
11 | 4. Create a new state version
12 | 5. Download a state file
13 |
14 | ### Conversation
15 |
16 | ```
17 | **User:** I need to examine the state versions in my "production" workspace and understand the outputs in the current state.
18 |
19 | **Claude:** I'll help you examine the state versions in your production workspace. Let me start by listing all the state versions.
20 |
21 | [Claude uses list_state_versions tool]
22 |
23 | I found 15 state versions in your production workspace. Here are the most recent ones:
24 |
25 | - State version 15 created on 2024-03-15 at 14:30 UTC (status: finalized)
26 | - State version 14 created on 2024-03-10 at 09:15 UTC (status: finalized)
27 | - State version 13 created on 2024-03-08 at 16:45 UTC (status: finalized)
28 |
29 | Now let me get the details of your current state version to understand what's deployed.
30 |
31 | [Claude uses get_workspace_details tool]
32 | [Claude uses get_current_state_version tool]
33 |
34 | Your current state (ID: sv-abc123def456) is at serial 15 and was created with Terraform version 1.6.2. It contains 47 managed resources including VPCs, security groups, EC2 instances, and RDS databases.
35 |
36 | Let me examine the outputs from this state version.
37 |
38 | [Claude uses list_state_version_outputs tool]
39 |
40 | Here are the outputs from your current state:
41 |
42 | - vpc_id (string): vpc-1234567890abcdef
43 | - database_endpoint (string): prod-db.abc123.us-east-1.rds.amazonaws.com
44 | - load_balancer_dns (string): prod-alb-123456789.us-east-1.elb.amazonaws.com
45 | - database_password (string): [SENSITIVE]
46 | - api_key (string): [SENSITIVE]
47 |
48 | The state includes 5 outputs total, with 2 marked as sensitive for security.
49 | ```
50 |
51 | ```
52 | **User:** I need to create a new state version for this workspace. I have a state file exported from my local environment that I want to upload.
53 |
54 | **Claude:** I'll help you create a new state version for your workspace using your local state file. This process requires several steps to ensure the state is properly uploaded and validated.
55 |
56 | First, I need to lock the workspace since state version creation requires exclusive access.
57 |
58 | [Claude uses lock_workspace tool]
59 |
60 | The workspace is now locked with the reason "Uploading new state version from local environment".
61 |
62 | Now I'll create the new state version using your local state file. I've processed your terraform.tfstate file and extracted the necessary information:
63 |
64 | - Serial number: 16 (incremented from current state)
65 | - MD5 hash: d41d8cd98f00b204e9800998ecf8427e
66 | - Lineage: 871d1b4a-e579-fb7c-ffdb-f0c858a647a7
67 |
68 | [Claude uses create_state_version tool]
69 |
70 | Great! I've successfully created the new state version with ID: sv-xyz789abc123. The state has been uploaded and is now being processed by Terraform Cloud.
71 |
72 | Let me unlock the workspace now that the upload is complete.
73 |
74 | [Claude uses unlock_workspace tool]
75 |
76 | The workspace is now unlocked and your new state version is active. The state contains 52 resources (5 more than the previous version) and includes the changes from your local environment.
77 | ```
78 |
79 | ```
80 | **User:** I want to see what resources are included in one of our state versions. Can I download a specific state version and examine it?
81 |
82 | **Claude:** Absolutely! I can help you examine the contents of a specific state version. Let me get the details of a state version and show you what resources it contains.
83 |
84 | Let me start by getting the details of state version sv-abc123def456:
85 |
86 | [Claude uses get_state_version tool]
87 |
88 | Great! This state version has been fully processed and contains detailed resource information. Here's what I found:
89 |
90 | **Resources in state (47 total):**
91 | - aws_vpc.main
92 | - aws_subnet.public_1a
93 | - aws_subnet.public_1b
94 | - aws_security_group.web
95 | - aws_security_group.database
96 | - aws_instance.web_server_1
97 | - aws_instance.web_server_2
98 | - aws_db_instance.main
99 | - aws_load_balancer.main
100 | - aws_route53_record.main
101 | - And 37 more resources...
102 |
103 | **Modules used:**
104 | - root module: 35 resources
105 | - module.networking: 8 resources
106 | - module.security: 4 resources
107 |
108 | **Providers in state:**
109 | - hashicorp/aws: 45 resources
110 | - hashicorp/random: 2 resources
111 |
112 | Now let me download the actual state file so you can examine it locally:
113 |
114 | [Claude uses download_state_file tool]
115 |
116 | I've downloaded the raw state file successfully. The state contains all the resource configurations and current values.
117 |
118 | I can also download it in JSON format since this state was created with Terraform 1.6.2:
119 |
120 | [Claude uses download_state_file tool with JSON format]
121 |
122 | Perfect! I've downloaded both the raw state file and the JSON-formatted version. The JSON format is easier to parse and examine programmatically.
123 |
124 | The state file has been saved locally as "downloaded_state.tfstate" for your inspection. You can now examine all the resource details, dependencies, and current values managed by Terraform.
125 | ```
126 |
127 | ## Summary
128 |
129 | In this conversation, we demonstrated how to:
130 |
131 | 1. **List state versions** - View all state versions in a workspace with their creation dates and status
132 | 2. **Examine current state** - Get details about the active state version including resource counts and Terraform version
133 | 3. **Review state outputs** - Access output values from the state, with proper handling of sensitive values
134 | 4. **Create new state versions** - Upload state from local environments with proper workspace locking
135 | 5. **Download and analyze state** - Retrieve state files in both raw and JSON formats for detailed examination
136 |
137 | These operations help in managing Terraform state, examining infrastructure outputs, and troubleshooting state-related issues without requiring technical implementation knowledge.
```
--------------------------------------------------------------------------------
/docs/models/apply.md:
--------------------------------------------------------------------------------
```markdown
1 | # Apply Models
2 |
3 | This document describes the data models used for apply operations in Terraform Cloud.
4 |
5 | ## Overview
6 |
7 | Apply models provide structure and validation for interacting with the Terraform Cloud Apply API. These models define apply statuses, execution details, and request validation for retrieving apply information and logs.
8 |
9 | ## Models Reference
10 |
11 | ### ApplyStatus
12 |
13 | **Type:** Enum (string)
14 |
15 | **Description:** Represents the possible states an apply can be in during its lifecycle.
16 |
17 | **Values:**
18 | - `pending`: Apply has not yet started
19 | - `queued`: Apply is queued for execution
20 | - `running`: Apply is currently executing
21 | - `errored`: Apply encountered an error
22 | - `canceled`: Apply was canceled
23 | - `finished`: Apply completed successfully
24 | - `unreachable`: Apply is in an unreachable state
25 |
26 | **Usage Context:**
27 | Used to determine the current state of an apply and whether it has completed successfully.
28 |
29 | ```python
30 | from terraform_cloud_mcp.models import ApplyStatus
31 |
32 | # Check the status of an apply
33 | if apply_response["data"]["attributes"]["status"] == ApplyStatus.FINISHED:
34 | print("Apply completed successfully")
35 | elif apply_response["data"]["attributes"]["status"] == ApplyStatus.ERRORED:
36 | print("Apply encountered an error")
37 | ```
38 |
39 | ### ApplyExecutionDetails
40 |
41 | **Type:** Object
42 |
43 | **Description:** Contains information about how an apply was executed, particularly for agent-based execution.
44 |
45 | **Fields:**
46 | - `agent_id` (string, optional): ID of the agent that executed the apply
47 | - `agent_name` (string, optional): Name of the agent that executed the apply
48 | - `agent_pool_id` (string, optional): ID of the agent pool the executing agent belongs to
49 | - `agent_pool_name` (string, optional): Name of the agent pool the executing agent belongs to
50 |
51 | **JSON representation:**
52 | ```json
53 | {
54 | "execution-details": {
55 | "agent-id": "agent-AbCdEfGhIjKlMnOp",
56 | "agent-name": "production-agent-01",
57 | "agent-pool-id": "apool-AbCdEfGhIjKlMnOp",
58 | "agent-pool-name": "Production Agents"
59 | }
60 | }
61 | ```
62 |
63 | **Notes:**
64 | - Field names in JSON responses use kebab-case format (e.g., "agent-id")
65 | - Field names in the model use snake_case format (e.g., agent_id)
66 |
67 | ### ApplyStatusTimestamps
68 |
69 | **Type:** Object
70 |
71 | **Description:** Captures timing information for various stages in an apply's lifecycle.
72 |
73 | **Fields:**
74 | - `queued_at` (string, optional): ISO8601 timestamp when the apply was queued
75 | - `started_at` (string, optional): ISO8601 timestamp when apply execution started
76 | - `finished_at` (string, optional): ISO8601 timestamp when apply execution completed
77 |
78 | **JSON representation:**
79 | ```json
80 | {
81 | "status-timestamps": {
82 | "queued-at": "2023-09-01T12:00:00Z",
83 | "started-at": "2023-09-01T12:01:00Z",
84 | "finished-at": "2023-09-01T12:05:00Z"
85 | }
86 | }
87 | ```
88 |
89 | **Notes:**
90 | - Field names in JSON responses use kebab-case format (e.g., "queued-at")
91 | - Field names in the model use snake_case format (e.g., queued_at)
92 | - All timestamp fields follow ISO8601 format
93 | - Can be used to calculate apply duration and queue waiting time
94 |
95 | ### ApplyRequest
96 |
97 | **Type:** Request Validation Model
98 |
99 | **Description:** Used to validate apply ID parameters in API requests.
100 |
101 | **Fields:**
102 | - `apply_id` (string, required): The ID of the apply to retrieve
103 | - Format: Must match pattern "apply-[a-zA-Z0-9]{16}"
104 | - Example: "apply-AbCdEfGhIjKlMnOp"
105 |
106 | **Validation Rules:**
107 | - Apply ID must start with "apply-" prefix
108 | - Must contain exactly 16 alphanumeric characters after the prefix
109 |
110 | **Used by:**
111 | - `get_apply_details` and `get_apply_logs` tool functions to validate the apply ID format before making API requests
112 |
113 | ### ApplyErroredStateRequest
114 |
115 | **Type:** Request Validation Model
116 |
117 | **Description:** Used to validate parameters for retrieving errored state information.
118 |
119 | **Fields:**
120 | - `apply_id` (string, required): The ID of the apply with a failed state upload
121 | - Format: Must match pattern "apply-[a-zA-Z0-9]{16}"
122 | - Example: "apply-AbCdEfGhIjKlMnOp"
123 |
124 | **Validation Rules:**
125 | - Apply ID must start with "apply-" prefix
126 | - Must contain exactly 16 alphanumeric characters after the prefix
127 |
128 | **Used by:**
129 | - `get_errored_state` tool function to validate the apply ID format before making API requests
130 |
131 | ## API Response Structure
132 |
133 | ### Apply Details Response
134 |
135 | ```json
136 | {
137 | "data": {
138 | "id": "apply-AbCdEfGhIjKlMnOp",
139 | "type": "applies",
140 | "attributes": {
141 | "status": "finished",
142 | "status-timestamps": {
143 | "queued-at": "2023-09-01T12:00:00Z",
144 | "started-at": "2023-09-01T12:01:00Z",
145 | "finished-at": "2023-09-01T12:05:00Z"
146 | },
147 | "log-read-url": "https://archivist.terraform.io/v1/object/apply-AbCdEfGhIjKlMnOp",
148 | "resource-additions": 3,
149 | "resource-changes": 2,
150 | "resource-destructions": 1,
151 | "execution-details": {
152 | "agent-id": "agent-AbCdEfGhIjKlMnOp",
153 | "agent-name": "production-agent-01",
154 | "agent-pool-id": "apool-AbCdEfGhIjKlMnOp",
155 | "agent-pool-name": "Production Agents"
156 | }
157 | },
158 | "relationships": {
159 | "state-versions": {
160 | "data": [
161 | {
162 | "id": "sv-AbCdEfGhIjKlMnOp",
163 | "type": "state-versions"
164 | }
165 | ]
166 | }
167 | }
168 | }
169 | }
170 | ```
171 |
172 | ### Apply Logs Response
173 |
174 | ```json
175 | {
176 | "content": "Terraform v1.4.6\nApplying changes...\nAWS instance: Creating...\nAWS instance: Creation complete\nApply complete! Resources: 1 added, 0 changed, 0 destroyed."
177 | }
178 | ```
179 |
180 | ### Errored State Response
181 |
182 | ```json
183 | {
184 | "terraform_state": {
185 | "version": 4,
186 | "terraform_version": "1.4.6",
187 | "serial": 15,
188 | "lineage": "12345678-90ab-cdef-1234-567890abcdef",
189 | "resources": [
190 | {
191 | "mode": "managed",
192 | "type": "aws_instance",
193 | "name": "example",
194 | "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
195 | "instances": [...]
196 | }
197 | ]
198 | }
199 | }
200 | ```
201 |
202 | ## Related Resources
203 |
204 | - [Apply Tools](../tools/apply.md)
205 | - [Run Models](run.md)
206 | - [Terraform Cloud API - Applies](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/applies)
```
--------------------------------------------------------------------------------
/docs/conversations/organization-entitlements-conversation.md:
--------------------------------------------------------------------------------
```markdown
1 | # Organization Entitlements - Example Conversation
2 |
3 | This document shows example conversations with Claude using the Terraform Cloud MCP organization entitlements feature.
4 |
5 | ## Viewing Basic Organization Entitlements
6 |
7 | ```
8 | **User**: Can you show me the entitlements for my organization "hashicorp"?
9 |
10 | **Claude**: I'll retrieve the entitlements for your "hashicorp" organization.
11 |
12 | [Claude uses get_organization_entitlements tool]
13 |
14 | Here are the entitlements for your "hashicorp" organization:
15 |
16 | **Features:**
17 | - Operations: True
18 | - Private Module Registry: True
19 | - Sentinel Policies: False
20 | - Teams: False
21 | - Cost Estimation: False
22 | - SSO: False
23 | - State Storage: True
24 | - VCS Integrations: True
25 | - Self-Serve Billing: True
26 | - Configuration Designer: True
27 |
28 | **Limits:**
29 | - User Limit: 5
30 | - Policy Limit: 5
31 | - Policy Set Limit: 1
32 | - Run Task Limit: 1
33 | - Run Task Workspace Limit: 10
34 |
35 | These entitlements indicate you're on a basic tier plan with access to core features like state storage, operations, and private module registry, but without premium features like SSO, teams, or Sentinel policies.
36 | ```
37 |
38 | ## Understanding Plan Features and Upgrades
39 |
40 | ```
41 | **User**: What features would I get if I upgraded my plan?
42 |
43 | **Claude**: Based on your current entitlements, if you upgraded your plan (likely to a Team or Enterprise tier), you would gain access to several premium features:
44 |
45 | 1. **Teams functionality** - Create and manage teams with different permission levels
46 | 2. **SSO (Single Sign-On)** - Enterprise identity management integration
47 | 3. **Sentinel Policies** - Advanced policy as code enforcement
48 | 4. **Cost Estimation** - Get cost estimates for your infrastructure changes
49 | 5. **Run Tasks** - Custom integrations that run during the plan/apply cycle
50 | 6. **Audit Logging** - Detailed activity logs for compliance
51 | 7. **Higher Limits** - Increased limits for:
52 | - Users (beyond your current 5-user limit)
53 | - Policy sets
54 | - Run tasks
55 |
56 | You might also gain access to:
57 | - Agents - Run Terraform in your own infrastructure
58 | - Global Run Tasks - Run tasks that apply across multiple workspaces
59 | - Module Tests Generation - Automated test creation for modules
60 |
61 | The exact features would depend on the specific tier you upgrade to. Would you like me to help you determine which plan would be best for your needs?
62 | ```
63 |
64 | ## Analyzing Usage Against Entitlements
65 |
66 | ```
67 | **User**: Can you tell me which features we're actually using in our current organization?
68 |
69 | **Claude**: To determine which features you're actually using in your organization, I'll need to check various aspects of your Terraform Cloud setup.
70 |
71 | [Claude uses get_organization_details tool]
72 | [Claude uses list_workspaces tool]
73 | [Claude uses list_runs_in_organization tool]
74 |
75 | Based on my analysis of your "hashicorp" organization:
76 |
77 | **Features You're Currently Using:**
78 | - State Storage: You have 12 workspaces with state files
79 | - Remote Operations: You've run 87 Terraform operations in the last month
80 | - Private Module Registry: You have 3 modules registered
81 | - VCS Integration: Connected to GitHub for 75% of your workspaces
82 |
83 | **Features Available But Not Used:**
84 | - Configuration Designer: Available but no evidence of usage
85 | - Self-Serve Billing: Available but limited usage patterns
86 |
87 | **Features Limited By Your Current Plan:**
88 | - Teams: You can't create teams (5 individual users maximum)
89 | - Sentinel Policies: Not available on your current plan
90 | - Cost Estimation: Not available on your current plan
91 | - SSO: Not available on your current plan
92 |
93 | Based on your usage patterns, you might benefit most from upgrading if you need:
94 | 1. More than 5 users (teams functionality)
95 | 2. Policy enforcement for governance
96 | 3. Cost visibility for your infrastructure
97 |
98 | Would you like more specific recommendations based on your organization's needs?
99 | ```
100 |
101 | ## Checking User Capacity Against Limits
102 |
103 | ```
104 | **User**: Are we close to hitting our user limit?
105 |
106 | **Claude**: Let me check your current user count against your limit.
107 |
108 | [Claude uses get_organization_entitlements tool]
109 |
110 | Based on your organization entitlements:
111 |
112 | - **User Limit**: 5 users
113 | - **Current Users**: 4 users
114 | - **Remaining Capacity**: 1 user (80% of limit utilized)
115 |
116 | You are approaching your user limit with 4 out of 5 available seats used. This means you only have 1 seat remaining before you hit your limit.
117 |
118 | If you're planning to add more team members soon, you might want to consider upgrading to a Team or Enterprise tier plan which would provide:
119 |
120 | 1. Higher or unlimited user seats
121 | 2. Teams functionality to manage user permissions more effectively
122 | 3. More granular access control options
123 |
124 | Would you like me to help you explore upgrade options to accommodate your growing team?
125 | ```
126 |
127 | ## Comparing Against Different Organizations
128 |
129 | ```
130 | **User**: How do our entitlements compare to our "hashicorp-staging" organization?
131 |
132 | **Claude**: I'll compare the entitlements between your "hashicorp" and "hashicorp-staging" organizations.
133 |
134 | [Claude uses get_organization_entitlements tool for both organizations]
135 |
136 | Here's a comparison of entitlements between your organizations:
137 |
138 | | Feature | hashicorp (Production) | hashicorp-staging |
139 | |---------|------------------------|-------------------|
140 | | **Core Features** | | |
141 | | Operations | ✓ | ✓ |
142 | | State Storage | ✓ | ✓ |
143 | | Private Module Registry | ✓ | ✓ |
144 | | VCS Integration | ✓ | ✓ |
145 | | **Premium Features** | | |
146 | | Teams | ✗ | ✓ |
147 | | Sentinel Policies | ✗ | ✓ |
148 | | Cost Estimation | ✗ | ✓ |
149 | | SSO | ✗ | ✗ |
150 | | **Limits** | | |
151 | | User Limit | 5 | 25 |
152 | | Policy Limit | 5 | 15 |
153 | | Run Task Limit | 1 | 5 |
154 |
155 | Interesting findings:
156 |
157 | 1. Your staging organization is actually on a higher tier plan with more premium features
158 | 2. The staging organization has significantly higher user and policy limits
159 | 3. Both organizations lack SSO, which is typically only available on Enterprise plans
160 |
161 | This suggests your staging environment might be used for testing advanced features before adopting them in production. Would you like me to recommend how to align these environments, or explain why certain features might be important to have in production?
162 | ```
```
--------------------------------------------------------------------------------
/terraform_cloud_mcp/configs/filter_configs.py:
--------------------------------------------------------------------------------
```python
1 | """Filter configurations for Terraform Cloud MCP."""
2 |
3 | from ..models.filters import FilterConfig, ResourceType
4 |
5 |
6 | # Audit-safe filter configurations - conservative filtering to preserve compliance data
7 | FILTER_CONFIGS = {
8 | ResourceType.WORKSPACE: FilterConfig(
9 | always_remove={
10 | # Only remove statistical aggregations - not audit-relevant
11 | "apply-duration-average",
12 | "plan-duration-average",
13 | "policy-check-failures",
14 | "run-failures",
15 | },
16 | list_remove={
17 | # Remove only internal system fields - preserve all user/audit tracking
18 | "workspace-kpis-runs-count",
19 | "unarchived-workspace-change-requests-count",
20 | },
21 | essential_relationships={
22 | "organization",
23 | "project",
24 | "current-run",
25 | "current-state-version",
26 | "current-configuration-version",
27 | },
28 | ),
29 | ResourceType.RUN: FilterConfig(
30 | # Preserve permissions, actions, source for audit trails
31 | always_remove=set(), # Don't filter anything critical
32 | list_remove=set(), # Preserve all data for audit context
33 | essential_relationships={
34 | "workspace",
35 | "plan",
36 | "apply",
37 | "cost-estimate",
38 | },
39 | ),
40 | ResourceType.ORGANIZATION: FilterConfig(
41 | always_remove={
42 | # Remove only internal system flags - preserve auth policy for audits
43 | "fair-run-queuing-enabled",
44 | "send-passing-statuses-for-untriggered-speculative-plans",
45 | },
46 | # Preserve created-at, trial-expires-at, permissions, saml-enabled, two-factor-conformant
47 | list_remove=set(),
48 | ),
49 | ResourceType.PROJECT: FilterConfig(
50 | # Preserve created-at, updated-at for audit trails
51 | list_remove=set(),
52 | essential_relationships={
53 | "organization",
54 | },
55 | ),
56 | ResourceType.VARIABLE: FilterConfig(
57 | # Preserve version-id and created-at for audit/change tracking
58 | always_remove=set(),
59 | list_remove=set(),
60 | ),
61 | ResourceType.PLAN: FilterConfig(
62 | # Preserve permissions for audit context
63 | always_remove=set(),
64 | read_remove={
65 | "resource-drift", # Detailed drift info can be filtered in reads
66 | },
67 | list_remove={
68 | # Only filter detailed execution info in lists - preserve timing for audits
69 | "execution-details",
70 | },
71 | essential_relationships={
72 | "run",
73 | "state-versions",
74 | },
75 | ),
76 | ResourceType.APPLY: FilterConfig(
77 | # Preserve permissions and status-timestamps for audit trails
78 | always_remove=set(),
79 | list_remove={
80 | # Only filter detailed execution info in lists
81 | "execution-details",
82 | },
83 | essential_relationships={
84 | "run",
85 | "state-versions",
86 | },
87 | ),
88 | ResourceType.STATE_VERSION: FilterConfig(
89 | always_remove={
90 | # Only remove VCS-specific fields that don't impact audit
91 | "vcs-commit-sha",
92 | "vcs-commit-url",
93 | },
94 | list_remove={
95 | # Remove only internal hosted URLs - can be derived when needed
96 | "hosted-state-download-url",
97 | "hosted-json-state-download-url",
98 | "hosted-state-upload-url",
99 | },
100 | essential_relationships={
101 | "workspace",
102 | "run",
103 | "outputs",
104 | },
105 | ),
106 | ResourceType.COST_ESTIMATE: FilterConfig(
107 | # Preserve status-timestamps for audit timeline
108 | always_remove=set(),
109 | read_remove=set(), # Preserve error messages for audit context
110 | list_remove={
111 | # Only remove detailed resource counts in lists
112 | "resources-count",
113 | },
114 | essential_relationships={
115 | "run",
116 | },
117 | ),
118 | ResourceType.ASSESSMENT: FilterConfig(
119 | # Preserve result-count, created-at, updated-at for audit tracking
120 | always_remove=set(),
121 | read_remove=set(), # Preserve log URLs for audit access
122 | list_remove=set(),
123 | essential_relationships={
124 | "workspace",
125 | },
126 | ),
127 | ResourceType.ACCOUNT: FilterConfig(
128 | always_remove={
129 | # Remove only personal/UI fields - preserve auth info for audits
130 | "password", # Never should be present anyway
131 | "avatar-url", # UI-only field
132 | },
133 | # Preserve is-sudo, is-site-admin, auth-method, etc. for security audits
134 | list_remove=set(),
135 | ),
136 | }
137 |
138 | # Path patterns for resource type detection (order matters for specificity)
139 | PATH_PATTERNS = [
140 | ("state-versions", ResourceType.STATE_VERSION),
141 | ("state-version-outputs", ResourceType.STATE_VERSION),
142 | ("assessment-results", ResourceType.ASSESSMENT),
143 | ("cost-estimates", ResourceType.COST_ESTIMATE),
144 | ("workspaces", ResourceType.WORKSPACE),
145 | ("runs", ResourceType.RUN),
146 | ("organizations", ResourceType.ORGANIZATION),
147 | ("projects", ResourceType.PROJECT),
148 | ("plans", ResourceType.PLAN),
149 | ("applies", ResourceType.APPLY),
150 | ("vars", ResourceType.VARIABLE),
151 | ("variables", ResourceType.VARIABLE),
152 | ("account/details", ResourceType.ACCOUNT),
153 | ("users", ResourceType.ACCOUNT),
154 | ]
155 |
156 | # Data type mapping for response-based detection
157 | DATA_TYPE_MAP = {
158 | "projects": ResourceType.PROJECT,
159 | "vars": ResourceType.VARIABLE,
160 | "runs": ResourceType.RUN,
161 | }
162 |
163 | # Resource type mapping for consistent filtering
164 | RESOURCE_TYPE_MAP = {
165 | "workspace": ResourceType.WORKSPACE,
166 | "workspaces": ResourceType.WORKSPACE,
167 | "run": ResourceType.RUN,
168 | "runs": ResourceType.RUN,
169 | "organization": ResourceType.ORGANIZATION,
170 | "organizations": ResourceType.ORGANIZATION,
171 | "project": ResourceType.PROJECT,
172 | "projects": ResourceType.PROJECT,
173 | "var": ResourceType.VARIABLE,
174 | "vars": ResourceType.VARIABLE,
175 | "plan": ResourceType.PLAN,
176 | "plans": ResourceType.PLAN,
177 | "apply": ResourceType.APPLY,
178 | "applies": ResourceType.APPLY,
179 | "state-version": ResourceType.STATE_VERSION,
180 | "state-versions": ResourceType.STATE_VERSION,
181 | "cost-estimate": ResourceType.COST_ESTIMATE,
182 | "cost-estimates": ResourceType.COST_ESTIMATE,
183 | "assessment-result": ResourceType.ASSESSMENT,
184 | "assessment-results": ResourceType.ASSESSMENT,
185 | "user": ResourceType.ACCOUNT,
186 | "users": ResourceType.ACCOUNT,
187 | }
188 |
```
--------------------------------------------------------------------------------
/docs/conversations/project-management-conversation.md:
--------------------------------------------------------------------------------
```markdown
1 | # Project Management Conversation Examples
2 |
3 | This document provides example conversations demonstrating how to use the project management tools in the Terraform Cloud MCP.
4 |
5 | ## Listing Projects in an Organization
6 |
7 | ```
8 | **User:** Can you list all projects in my organization jptest-org-1?
9 |
10 | **Claude:** I'll list the projects in that organization for you.
11 |
12 | [Claude uses list_projects tool]
13 |
14 | Here are the projects in jptest-org-1:
15 |
16 | 1. Development Infrastructure (prj-abc123def456)
17 | - 5 workspaces
18 | - Created: 2025-01-15
19 |
20 | 2. Production Systems (prj-ghi789jkl012)
21 | - 8 workspaces
22 | - Created: 2024-12-01
23 |
24 | 3. CI/CD Pipeline (prj-mno345pqr678)
25 | - 3 workspaces
26 | - Created: 2025-02-10
27 |
28 | Would you like more details on any specific project?
29 | ```
30 |
31 | ## Getting Project Details
32 |
33 | ```
34 | **User:** I'd like to see details for project prj-abc123def456
35 |
36 | **Claude:** I'll retrieve the project details for you.
37 |
38 | [Claude uses get_project_details tool]
39 |
40 | Here are the details for project "Development Infrastructure" (prj-abc123def456):
41 |
42 | Description: Resources for the development environment
43 | Created: 2025-01-15T09:30:22Z
44 | Last updated: 2025-03-20T14:15:43Z
45 |
46 | Tags:
47 | - environment: development
48 | - team: platform
49 | - cost-center: 12345
50 |
51 | Contains 5 workspaces:
52 | - dev-networking
53 | - dev-compute
54 | - dev-storage
55 | - dev-databases
56 | - dev-monitoring
57 |
58 | No auto-destroy schedules are configured for this project.
59 | ```
60 |
61 | ## Creating a New Project
62 |
63 | ```
64 | **User:** I'd like to create a new project called "QA Environment" in organization jptest-org-1
65 |
66 | **Claude:** I'll create that project for you.
67 |
68 | [Claude uses create_project tool]
69 |
70 | I've created your new project "QA Environment" in jptest-org-1.
71 |
72 | Project ID: prj-stu901vwx234
73 | Created: 2025-04-26T15:45:12Z
74 |
75 | The project currently has no workspaces associated with it. Would you like to add any workspaces to this project or configure additional settings like tags?
76 | ```
77 |
78 | ## Creating a Project with Detailed Settings
79 |
80 | ```
81 | **User:** Create a project called "Compliance Systems" in jptest-org-1 with a description, environment tag set to "compliance", and configured to auto-destroy resources after 14 days of inactivity
82 |
83 | **Claude:** I'll create that project with your specified settings.
84 |
85 | [Claude uses create_project tool]
86 |
87 | I've created your new project "Compliance Systems" in jptest-org-1.
88 |
89 | Project ID: prj-yz1234abcd56
90 | Created: 2025-04-26T15:48:30Z
91 | Description: Systems for regulatory compliance
92 |
93 | Tags:
94 | - environment: compliance
95 |
96 | Auto-destroy configured: Resources will be destroyed after 14 days of inactivity.
97 |
98 | The project is ready for use. Would you like to add any workspaces to it now?
99 | ```
100 |
101 | ## Updating a Project
102 |
103 | ```
104 | **User:** I need to update the "Development Infrastructure" project (prj-abc123def456) to change its description and add a new tag
105 |
106 | **Claude:** I'll update that project for you.
107 |
108 | [Claude uses update_project tool]
109 |
110 | I've updated the "Development Infrastructure" project (prj-abc123def456).
111 |
112 | The description has been changed to "Development environment resources and infrastructure".
113 | Added tag: priority: medium
114 |
115 | The project now has the following tags:
116 | - environment: development
117 | - team: platform
118 | - cost-center: 12345
119 | - priority: medium
120 |
121 | All other settings remain unchanged.
122 | ```
123 |
124 | ## Viewing Project Tag Bindings
125 |
126 | ```
127 | **User:** What tags are applied to the "Production Systems" project (prj-ghi789jkl012)?
128 |
129 | **Claude:** I'll check the tags for that project.
130 |
131 | [Claude uses list_project_tag_bindings tool]
132 |
133 | The "Production Systems" project (prj-ghi789jkl012) has the following tags:
134 |
135 | - environment: production
136 | - team: platform
137 | - cost-center: 67890
138 | - criticality: high
139 | - compliance: soc2
140 | - backup-policy: daily
141 |
142 | These tags are used for organization, filtering, and governance purposes in your Terraform Cloud organization.
143 | ```
144 |
145 | ## Adding Tags to a Project
146 |
147 | ```
148 | **User:** I'd like to add two tags to the "CI/CD Pipeline" project (prj-mno345pqr678): category=pipeline and owner=devops-team
149 |
150 | **Claude:** I'll add those tags to the project.
151 |
152 | [Claude uses add_update_project_tag_bindings tool]
153 |
154 | I've added the tags to the "CI/CD Pipeline" project:
155 |
156 | Added tags:
157 | - category: pipeline
158 | - owner: devops-team
159 |
160 | The project now has a total of 5 tags:
161 | - environment: shared
162 | - team: devops
163 | - category: pipeline
164 | - owner: devops-team
165 | - priority: high
166 | ```
167 |
168 | ## Moving Workspaces to a Project
169 |
170 | ```
171 | **User:** I need to move the workspaces "test-network" and "test-compute" (IDs: ws-def456ghi789 and ws-jkl012mno345) to the "QA Environment" project (prj-stu901vwx234)
172 |
173 | **Claude:** I'll move those workspaces to the QA Environment project.
174 |
175 | [Claude uses move_workspaces_to_project tool]
176 |
177 | I've successfully moved both workspaces to the "QA Environment" project:
178 |
179 | - "test-network" (ws-def456ghi789)
180 | - "test-compute" (ws-jkl012mno345)
181 |
182 | These workspaces will now inherit any project-level settings from the QA Environment project, such as tag bindings. The workspaces' individual settings remain unchanged.
183 |
184 | The QA Environment project now has 2 workspaces associated with it.
185 | ```
186 |
187 | ## Deleting a Project
188 |
189 | ```
190 | **User:** I want to delete the project "Compliance Systems" (prj-yz1234abcd56)
191 |
192 | **Claude:** I'll delete that project for you.
193 |
194 | [Claude uses delete_project tool]
195 |
196 | The "Compliance Systems" project (prj-yz1234abcd56) has been successfully deleted.
197 |
198 | Note that this only deleted the project itself. Any workspaces that were in this project have been moved back to the organization's default project. No workspaces or infrastructure resources were deleted by this action.
199 | ```
200 |
201 | ## Finding Projects by Search Query
202 |
203 | ```
204 | **User:** Can you find all projects in jptest-org-1 that have to do with development?
205 |
206 | **Claude:** I'll search for development-related projects.
207 |
208 | [Claude uses list_projects tool]
209 |
210 | I found 2 projects related to "development" in jptest-org-1:
211 |
212 | 1. Development Infrastructure (prj-abc123def456)
213 | - 5 workspaces
214 | - Description: Development environment resources and infrastructure
215 | - Tags: environment:development, team:platform, cost-center:12345, priority:medium
216 |
217 | 2. API Development (prj-pqr678stu901)
218 | - 3 workspaces
219 | - Description: API development and testing
220 | - Tags: environment:development, team:api, service:rest
221 |
222 | Would you like more details about either of these projects?
223 | ```
224 |
225 | ## Handling Project Errors
226 |
227 | ```
228 | **User:** Delete project prj-nonexistent123456
229 |
230 | **Claude:** I'll try to delete that project.
231 |
232 | [Claude uses delete_project tool]
233 |
234 | I wasn't able to delete the project. The system returned an error indicating that project ID "prj-nonexistent123456" doesn't exist.
235 |
236 | Would you like me to list the available projects in your organization so you can confirm the correct ID?
237 | ```
```
--------------------------------------------------------------------------------
/terraform_cloud_mcp/models/filters.py:
--------------------------------------------------------------------------------
```python
1 | """Filter models for Terraform Cloud MCP.
2 |
3 | This module defines Pydantic models and enums for API response filtering,
4 | providing type-safe configuration and validation for filter operations.
5 |
6 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs
7 | """
8 |
9 | from typing import Set, Optional
10 | from pydantic import Field, field_validator
11 | from enum import Enum
12 |
13 | from .base import BaseModelConfig
14 |
15 |
16 | class OperationType(str, Enum):
17 | """Operation types for API filtering.
18 |
19 | Defines the type of API operation being performed, which affects
20 | how responses are filtered:
21 | - READ: Single resource retrieval operations
22 | - LIST: Multiple resource listing operations
23 | - MANAGE: Create, update, delete operations
24 |
25 | See:
26 | docs/models/filters.md for reference
27 | """
28 |
29 | READ = "read"
30 | LIST = "list"
31 | MANAGE = "manage"
32 |
33 |
34 | class ResourceType(str, Enum):
35 | """Known resource types for filtering.
36 |
37 | Defines the Terraform Cloud resource types that have specific
38 | filtering configurations. Each type has tailored field removal
39 | rules optimized for token efficiency.
40 |
41 | See:
42 | docs/models/filters.md for reference
43 | """
44 |
45 | WORKSPACE = "workspace"
46 | RUN = "run"
47 | ORGANIZATION = "organization"
48 | PROJECT = "project"
49 | VARIABLE = "variable"
50 | PLAN = "plan"
51 | APPLY = "apply"
52 | STATE_VERSION = "state-version"
53 | COST_ESTIMATE = "cost-estimate"
54 | ASSESSMENT = "assessment"
55 | ACCOUNT = "account"
56 | GENERIC = "generic"
57 |
58 |
59 | class FilterConfig(BaseModelConfig):
60 | """Configuration for filtering a specific resource type.
61 |
62 | Defines which fields should be removed from API responses for different
63 | operation types to reduce token usage while preserving essential data.
64 |
65 | Attributes:
66 | always_remove: Fields to always remove regardless of operation type
67 | read_remove: Additional fields to remove for read operations
68 | list_remove: Additional fields to remove for list operations
69 | essential_relationships: Essential relationships to keep for read operations
70 |
71 | Example:
72 | config = FilterConfig(
73 | always_remove={"permissions", "actions"},
74 | list_remove={"created-at", "updated-at"},
75 | essential_relationships={"organization", "project"}
76 | )
77 |
78 | See:
79 | docs/models/filters.md for reference
80 | """
81 |
82 | always_remove: Set[str] = Field(
83 | default_factory=set,
84 | description="Fields to always remove regardless of operation type",
85 | )
86 | read_remove: Set[str] = Field(
87 | default_factory=set,
88 | description="Additional fields to remove for read operations",
89 | )
90 | list_remove: Set[str] = Field(
91 | default_factory=set,
92 | description="Additional fields to remove for list operations",
93 | )
94 | essential_relationships: Optional[Set[str]] = Field(
95 | default=None, description="Essential relationships to keep for read operations"
96 | )
97 |
98 | @field_validator("always_remove", "read_remove", "list_remove")
99 | @classmethod
100 | def validate_field_names(cls, v: Set[str]) -> Set[str]:
101 | """Validate that field names are non-empty strings.
102 |
103 | Args:
104 | v: Set of field names to validate
105 |
106 | Returns:
107 | Validated set of field names
108 |
109 | Raises:
110 | ValueError: If any field names are empty or not strings
111 | """
112 | if not v:
113 | return v
114 |
115 | invalid_fields = {
116 | field
117 | for field in v
118 | if not field or not isinstance(field, str) or not field.strip()
119 | }
120 | if invalid_fields:
121 | raise ValueError(f"Field names must be non-empty strings: {invalid_fields}")
122 |
123 | return v
124 |
125 | @field_validator("essential_relationships")
126 | @classmethod
127 | def validate_essential_relationships(
128 | cls, v: Optional[Set[str]]
129 | ) -> Optional[Set[str]]:
130 | """Validate essential relationships if provided.
131 |
132 | Args:
133 | v: Set of relationship names to validate
134 |
135 | Returns:
136 | Validated set of relationship names
137 |
138 | Raises:
139 | ValueError: If any relationship names are empty or not strings
140 | """
141 | if v is None:
142 | return v
143 |
144 | invalid_rels = {
145 | rel for rel in v if not rel or not isinstance(rel, str) or not rel.strip()
146 | }
147 | if invalid_rels:
148 | raise ValueError(
149 | f"Relationship names must be non-empty strings: {invalid_rels}"
150 | )
151 |
152 | return v
153 |
154 |
155 | class FilterRequest(BaseModelConfig):
156 | """Request parameters for filtering operations.
157 |
158 | Provides a structured way to specify filtering parameters for API responses,
159 | including resource type, operation type, and custom field specifications.
160 |
161 | Attributes:
162 | resource_type: Type of resource being filtered
163 | operation_type: Type of operation being performed
164 | custom_fields: Optional custom fields to remove beyond default configuration
165 | preserve_fields: Optional fields to preserve even if normally filtered
166 |
167 | Example:
168 | request = FilterRequest(
169 | resource_type=ResourceType.WORKSPACE,
170 | operation_type=OperationType.LIST,
171 | custom_fields={"debug-info", "verbose-logs"}
172 | )
173 |
174 | See:
175 | docs/models/filters.md for reference
176 | """
177 |
178 | resource_type: ResourceType = Field(description="Type of resource being filtered")
179 | operation_type: OperationType = Field(
180 | default=OperationType.READ, description="Type of operation being performed"
181 | )
182 | custom_fields: Optional[Set[str]] = Field(
183 | default=None,
184 | description="Optional custom fields to remove beyond default configuration",
185 | )
186 | preserve_fields: Optional[Set[str]] = Field(
187 | default=None,
188 | description="Optional fields to preserve even if normally filtered",
189 | )
190 |
191 | @field_validator("custom_fields", "preserve_fields")
192 | @classmethod
193 | def validate_custom_fields(cls, v: Optional[Set[str]]) -> Optional[Set[str]]:
194 | """Validate custom field specifications.
195 |
196 | Args:
197 | v: Set of custom field names to validate
198 |
199 | Returns:
200 | Validated set of custom field names
201 |
202 | Raises:
203 | ValueError: If any field names are empty or not strings
204 | """
205 | if v is None:
206 | return v
207 |
208 | invalid_fields = {
209 | field
210 | for field in v
211 | if not field or not isinstance(field, str) or not field.strip()
212 | }
213 | if invalid_fields:
214 | raise ValueError(
215 | f"Custom field names must be non-empty strings: {invalid_fields}"
216 | )
217 |
218 | return v
219 |
```
--------------------------------------------------------------------------------
/terraform_cloud_mcp/api/client.py:
--------------------------------------------------------------------------------
```python
1 | """Terraform Cloud API client"""
2 |
3 | import logging
4 | from typing import Optional, Dict, TypeVar, Union, Any
5 | import httpx
6 | from pydantic import BaseModel
7 |
8 | from ..utils.env import get_tfc_token, should_return_raw_response, get_tfc_address
9 | from ..utils.filters import (
10 | get_response_filter,
11 | should_filter_response,
12 | detect_resource_type,
13 | detect_operation_type,
14 | )
15 |
16 | DEFAULT_TOKEN = get_tfc_token()
17 | logger = logging.getLogger(__name__)
18 |
19 | if DEFAULT_TOKEN:
20 | logger.info("Default token provided (masked for security)")
21 |
22 |
23 | # Type variable for generic request models
24 | ReqT = TypeVar("ReqT", bound=BaseModel)
25 |
26 |
27 | async def api_request(
28 | path: str,
29 | method: str = "GET",
30 | token: Optional[str] = None,
31 | params: Dict[str, Any] = {},
32 | data: Union[Dict[str, Any], BaseModel] = {},
33 | external_url: bool = False,
34 | accept_text: bool = False,
35 | raw_response: Optional[bool] = None,
36 | ) -> Dict[str, Any]:
37 | """Make a request to the Terraform Cloud API with proper error handling."""
38 | token = token or DEFAULT_TOKEN
39 | if not token:
40 | return {
41 | "error": "Token is required. Please set the TFC_TOKEN environment variable."
42 | }
43 |
44 | # Convert Pydantic models to dict
45 | request_data = (
46 | data.model_dump(exclude_unset=True) if isinstance(data, BaseModel) else data
47 | )
48 |
49 | headers = {
50 | "Authorization": f"Bearer {token}",
51 | "Content-Type": "application/vnd.api+json",
52 | }
53 |
54 | async with httpx.AsyncClient(follow_redirects=False) as client:
55 | tfc_address = get_tfc_address()
56 | url = path if external_url else f"{tfc_address}/api/v2/{path}"
57 | kwargs: Dict[str, Any] = {"headers": headers, "params": params}
58 | if request_data:
59 | kwargs["json"] = request_data
60 |
61 | try:
62 | response = await client.request(method, url, **kwargs)
63 |
64 | # Handle redirects manually
65 | if response.status_code in (301, 302, 307, 308):
66 | location = response.headers.get("Location")
67 | if not location:
68 | return {
69 | "error": "Redirect received, but no Location header provided."
70 | }
71 | return await handle_redirect(
72 | location, headers, client, accept_text, path, method, raw_response
73 | )
74 |
75 | # For text responses
76 | if accept_text:
77 | return {"content": response.text}
78 |
79 | # Handle 204 No Content responses
80 | if response.status_code == 204:
81 | return {"status": "success", "status_code": 204}
82 |
83 | # Handle other success responses
84 | json_data = response.json()
85 | # Ensure we return a dict as specified in the function signature
86 | if not isinstance(json_data, dict):
87 | json_data = {"data": json_data}
88 |
89 | # Apply response filtering if not disabled
90 | return _apply_response_filtering(json_data, path, method, raw_response)
91 |
92 | except httpx.RequestError as e:
93 | logger.error(f"Network error while making request to {url}: {e}")
94 | return {"error": f"Network error: {str(e)}"}
95 | except ValueError as e:
96 | if accept_text and "response" in locals():
97 | return {"content": response.text}
98 | logger.error(f"Failed to parse JSON response from {url}: {e}")
99 | return {"error": f"Failed to parse JSON response: {str(e)}"}
100 | except Exception as e:
101 | logger.error(f"Unexpected error while making request to {url}: {e}")
102 | return {"error": f"Unexpected error: {str(e)}"}
103 |
104 |
105 | async def handle_redirect(
106 | location: str,
107 | headers: Dict[str, str],
108 | client: httpx.AsyncClient,
109 | accept_text: bool = False,
110 | original_path: str = "",
111 | original_method: str = "GET",
112 | raw_response: Optional[bool] = None,
113 | ) -> Dict[str, Any]:
114 | """Handle redirects manually, ensuring headers are forwarded."""
115 | try:
116 | response = await client.get(location, headers=headers)
117 | if 200 <= response.status_code < 300:
118 | # For text responses
119 | if accept_text:
120 | return {"content": response.text}
121 |
122 | # Parse the response as JSON and ensure it is a dictionary
123 | json_data = response.json()
124 | if not isinstance(json_data, dict):
125 | json_data = {"data": json_data}
126 |
127 | # Apply response filtering if not disabled
128 | return _apply_response_filtering(
129 | json_data, original_path, original_method, raw_response
130 | )
131 | return {
132 | "error": f"Redirect request failed: {response.status_code}",
133 | "redirect_url": location,
134 | }
135 | except httpx.RequestError as e:
136 | return {
137 | "error": f"Failed to follow redirect due to network error: {str(e)}",
138 | "redirect_url": location,
139 | }
140 | except ValueError as e:
141 | # Try returning text content if we're expecting text
142 | if accept_text and "response" in locals():
143 | return {"content": response.text}
144 | return {
145 | "error": f"Failed to parse JSON response: {str(e)}",
146 | "redirect_url": location,
147 | }
148 | except Exception as e:
149 | return {
150 | "error": f"Unexpected error while following redirect: {str(e)}",
151 | "redirect_url": location,
152 | }
153 |
154 |
155 | def _apply_response_filtering(
156 | json_data: Dict[str, Any],
157 | path: str,
158 | method: str,
159 | raw_response: Optional[bool] = None,
160 | ) -> Dict[str, Any]:
161 | """Apply response filtering based on configuration and request context."""
162 | # Check if raw response is requested
163 | if raw_response is True or (raw_response is None and should_return_raw_response()):
164 | return json_data
165 |
166 | # Check if this response should be filtered
167 | if not should_filter_response(path, method):
168 | return json_data
169 |
170 | try:
171 | # Detect resource type and operation type
172 | resource_type = detect_resource_type(path, json_data)
173 | operation_type = detect_operation_type(path, method)
174 |
175 | # Get and apply the appropriate filter
176 | filter_func = get_response_filter(resource_type)
177 | filtered_data = filter_func(json_data, operation_type)
178 |
179 | logger.info(
180 | f"Applied {resource_type} filter ({filter_func.__name__}) for {operation_type} operation on {path}"
181 | )
182 | return dict(filtered_data)
183 |
184 | except Exception as e:
185 | # If filtering fails, log error and return raw data
186 | logger.warning(
187 | f"Response filtering failed for {path}: {e}. Returning raw response."
188 | )
189 | return json_data
190 |
```
--------------------------------------------------------------------------------
/docs/tools/project.md:
--------------------------------------------------------------------------------
```markdown
1 | # Project Tools
2 |
3 | This module provides tools for managing projects in Terraform Cloud.
4 |
5 | ## Overview
6 |
7 | Projects in Terraform Cloud are containers for workspaces that help organize them into logical groups. These tools allow you to create, read, update, and delete projects, as well as manage tag bindings and move workspaces between projects.
8 |
9 | ## API Reference
10 |
11 | These tools interact with the Terraform Cloud Projects API:
12 | - [Projects API Documentation](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects)
13 | - [Projects Guide](https://developer.hashicorp.com/terraform/cloud-docs/projects)
14 |
15 | ## Tools Reference
16 |
17 | ### list_projects
18 |
19 | **Function:** `list_projects(organization: str, page_number: int = 1, page_size: int = 20, q: Optional[str] = None, filter_names: Optional[str] = None, filter_permissions_update: Optional[bool] = None, filter_permissions_create_workspace: Optional[bool] = None, sort: Optional[str] = None) -> Dict[str, Any]`
20 |
21 | **Description:** Retrieves a paginated list of projects in an organization.
22 |
23 | **Parameters:**
24 | - `organization` (str): The organization name
25 | - `page_number` (int, optional): Page number to fetch (default: 1)
26 | - `page_size` (int, optional): Number of results per page (default: 20, max: 100)
27 | - `q` (str, optional): Search query to filter projects by name
28 | - `filter_names` (str, optional): Filter projects by name (comma-separated list)
29 | - `filter_permissions_update` (bool, optional): Filter projects that the user can update
30 | - `filter_permissions_create_workspace` (bool, optional): Filter projects that the user can create workspaces in
31 | - `sort` (str, optional): Sort projects by name ('name' or '-name' for descending)
32 |
33 | **Returns:** JSON response containing paginated list of projects with their configuration and metadata.
34 |
35 | **Notes:**
36 | - Requires "list projects" permission on the organization
37 | - Use the search parameter for partial name matches
38 | - Permissions filters are useful for determining which projects you can modify
39 |
40 | ### get_project_details
41 |
42 | **Function:** `get_project_details(project_id: str) -> Dict[str, Any]`
43 |
44 | **Description:** Retrieves comprehensive information about a specific project.
45 |
46 | **Parameters:**
47 | - `project_id` (str): The ID of the project to retrieve details for (format: "prj-xxxxxxxx")
48 |
49 | **Returns:** JSON response with project details including:
50 | - Name and description
51 | - Creation and update timestamps
52 | - Auto-destroy activity duration settings
53 | - Tag bindings
54 | - Workspace count
55 |
56 | **Notes:**
57 | - Requires "show project" permission
58 | - Essential for retrieving tag bindings and workspace counts
59 |
60 | ### create_project
61 |
62 | **Function:** `create_project(organization: str, name: str, params: Optional[ProjectParams] = None) -> Dict[str, Any]`
63 |
64 | **Description:** Creates a new project in an organization.
65 |
66 | **Parameters:**
67 | - `organization` (str): The organization name
68 | - `name` (str): The name for the new project
69 | - `params` (ProjectParams, optional): Additional configuration options:
70 | - `description`: Human-readable description of the project
71 | - `auto_destroy_activity_duration`: How long each workspace should wait before auto-destroying
72 | - `tag_bindings`: List of tag key-value pairs to bind to the project
73 |
74 | **Returns:** JSON response with the created project details.
75 |
76 | **Notes:**
77 | - Requires "create projects" permission on the organization
78 | - Project names must be unique within an organization
79 | - Tags bound to the project are inherited by workspaces within the project
80 |
81 | ### update_project
82 |
83 | **Function:** `update_project(project_id: str, params: Optional[ProjectParams] = None) -> Dict[str, Any]`
84 |
85 | **Description:** Updates an existing project's settings.
86 |
87 | **Parameters:**
88 | - `project_id` (str): The ID of the project to update
89 | - `params` (ProjectParams, optional): Settings to update:
90 | - `name`: New name for the project
91 | - `description`: Human-readable description
92 | - `auto_destroy_activity_duration`: How long each workspace should wait before auto-destroying
93 |
94 | **Returns:** JSON response with the updated project details.
95 |
96 | **Notes:**
97 | - Requires "update project" permission
98 | - Only specified attributes will be updated
99 | - Does not update tag bindings directly (use add_update_project_tag_bindings)
100 |
101 | ### delete_project
102 |
103 | **Function:** `delete_project(project_id: str) -> Dict[str, Any]`
104 |
105 | **Description:** Permanently deletes a project.
106 |
107 | **Parameters:**
108 | - `project_id` (str): The ID of the project to delete
109 |
110 | **Returns:** Empty response with HTTP 204 status code if successful.
111 |
112 | **Notes:**
113 | - Requires "delete project" permission
114 | - Will fail if the project contains any workspaces or stacks
115 | - Move or delete workspaces first before deleting a project
116 |
117 | ### list_project_tag_bindings
118 |
119 | **Function:** `list_project_tag_bindings(project_id: str) -> Dict[str, Any]`
120 |
121 | **Description:** Lists all tags bound to a specific project.
122 |
123 | **Parameters:**
124 | - `project_id` (str): The ID of the project
125 |
126 | **Returns:** JSON response with list of tag bindings including key-value pairs.
127 |
128 | **Notes:**
129 | - Requires "show project" permission
130 | - Project tag bindings are inherited by all workspaces within the project
131 | - Useful for understanding which tags will be applied to workspaces
132 |
133 | ### add_update_project_tag_bindings
134 |
135 | **Function:** `add_update_project_tag_bindings(project_id: str, tag_bindings: List[TagBinding]) -> Dict[str, Any]`
136 |
137 | **Description:** Adds or updates tag bindings on a project.
138 |
139 | **Parameters:**
140 | - `project_id` (str): The ID of the project
141 | - `tag_bindings`: List of TagBinding objects with key-value pairs
142 |
143 | **Returns:** JSON response with the complete list of updated tag bindings.
144 |
145 | **Notes:**
146 | - Requires "update project" permission
147 | - This is an additive operation (doesn't remove existing tags)
148 | - If a key already exists, its value will be updated
149 | - Tags are automatically propagated to all workspaces in the project
150 |
151 | ### move_workspaces_to_project
152 |
153 | **Function:** `move_workspaces_to_project(project_id: str, workspace_ids: List[str]) -> Dict[str, Any]`
154 |
155 | **Description:** Moves one or more workspaces into a project.
156 |
157 | **Parameters:**
158 | - `project_id` (str): The ID of the destination project
159 | - `workspace_ids`: List of workspace IDs to move
160 |
161 | **Returns:** Empty response with HTTP 204 status code if successful.
162 |
163 | **Notes:**
164 | - Requires permission to move workspaces on both source and destination projects
165 | - Workspaces will inherit tags from the destination project
166 | - Useful for reorganizing workspaces between projects
167 |
168 | **Common Error Scenarios:**
169 |
170 | | Error | Cause | Solution |
171 | |-------|-------|----------|
172 | | 404 | Project not found | Verify the project ID |
173 | | 403 | Insufficient permissions | Ensure you have proper permissions on projects |
174 | | 422 | Project contains workspaces | Move workspaces out before deleting |
175 | | 422 | Duplicate tag keys | Remove duplicates from tag binding list |
```
--------------------------------------------------------------------------------
/docs/models/project.md:
--------------------------------------------------------------------------------
```markdown
1 | # Project Models
2 |
3 | This document describes the data models used for project operations in Terraform Cloud.
4 |
5 | ## Overview
6 |
7 | Project models provide structure and validation for interacting with the Terraform Cloud Projects API. These models define project configuration options, tag bindings, and other settings that can be applied to projects and inherited by their workspaces.
8 |
9 | ## Models Reference
10 |
11 | ### TagBinding
12 |
13 | **Type:** Object
14 |
15 | **Description:** Tag binding configuration for a project. Defines a tag key-value pair that can be bound to a project and inherited by its workspaces.
16 |
17 | **Fields:**
18 | - `key` (string, required): The key of the tag
19 | - `value` (string, required): The value of the tag
20 |
21 | **JSON representation:**
22 | ```json
23 | {
24 | "key": "environment",
25 | "value": "production"
26 | }
27 | ```
28 |
29 | **Usage Context:**
30 | Tag bindings can be applied to projects and are inherited by all workspaces within those projects. They provide a way to consistently categorize and organize workspaces that share common characteristics.
31 |
32 | ### ProjectParams
33 |
34 | **Type:** Object
35 |
36 | **Description:** Parameters for project operations without routing fields. Used to specify configuration options when creating or updating projects.
37 |
38 | **Fields:**
39 | - `name` (string, optional): Name of the project
40 | - `description` (string, optional): Human-readable description of the project
41 | - `auto_destroy_activity_duration` (string, optional): How long each workspace should wait before auto-destroying (e.g., '14d', '24h')
42 | - `tag_bindings` (List[TagBinding], optional): List of tag key-value pairs to bind to the project
43 |
44 | **JSON representation:**
45 | ```json
46 | {
47 | "data": {
48 | "type": "projects",
49 | "attributes": {
50 | "name": "Production Infrastructure",
51 | "description": "Production environment resources",
52 | "auto-destroy-activity-duration": "14d"
53 | }
54 | }
55 | }
56 | ```
57 |
58 | **Notes:**
59 | - Field names in JSON use kebab-case format (e.g., "auto-destroy-activity-duration")
60 | - Field names in the model use snake_case format (e.g., auto_destroy_activity_duration)
61 | - All fields are optional when updating but name is required when creating
62 |
63 | ### ProjectListRequest
64 |
65 | **Type:** Request Validation Model
66 |
67 | **Description:** Used to validate parameters for listing projects.
68 |
69 | **Fields:**
70 | - `organization` (string, required): The name of the organization to list projects from
71 | - `page_number` (int, optional): Page number to fetch (default: 1)
72 | - `page_size` (int, optional): Number of results per page (default: 20, max: 100)
73 | - `q` (string, optional): Search query to filter projects by name
74 | - `filter_names` (string, optional): Filter projects by name (comma-separated list)
75 | - `filter_permissions_update` (bool, optional): Filter projects that the user can update
76 | - `filter_permissions_create_workspace` (bool, optional): Filter projects that the user can create workspaces in
77 | - `sort` (string, optional): Sort projects by name ('name' or '-name' for descending)
78 |
79 | **Used by:**
80 | - `list_projects` tool function to validate listing parameters
81 |
82 | ### BaseProjectRequest
83 |
84 | **Type:** Request Validation Model
85 |
86 | **Description:** Base request model containing common fields for project operations.
87 |
88 | **Fields:**
89 | - Includes all fields from ProjectParams
90 |
91 | ### ProjectCreateRequest
92 |
93 | **Type:** Request Validation Model
94 |
95 | **Description:** Used to validate parameters for creating a project.
96 |
97 | **Fields:**
98 | - `organization` (string, required): The organization name
99 | - `name` (string, required): The name for the new project
100 | - `params` (ProjectParams, optional): Additional configuration options
101 |
102 | **Used by:**
103 | - `create_project` tool function to validate project creation parameters
104 |
105 | ### ProjectUpdateRequest
106 |
107 | **Type:** Request Validation Model
108 |
109 | **Description:** Used to validate parameters for updating a project.
110 |
111 | **Fields:**
112 | - `project_id` (string, required): The ID of the project to update
113 | - `params` (ProjectParams, optional): Settings to update
114 |
115 | **Used by:**
116 | - `update_project` tool function to validate project update parameters
117 |
118 | ### ProjectTagBindingRequest
119 |
120 | **Type:** Request Validation Model
121 |
122 | **Description:** Used to validate tag binding operations for projects.
123 |
124 | **Fields:**
125 | - `project_id` (string, required): The ID of the project
126 |
127 | **Used by:**
128 | - `list_project_tag_bindings` tool function to validate project ID
129 |
130 | ### WorkspaceMoveRequest
131 |
132 | **Type:** Request Validation Model
133 |
134 | **Description:** Used to validate workspace move operations.
135 |
136 | **Fields:**
137 | - `project_id` (string, required): The ID of the destination project
138 | - `workspace_ids` (List[string], required): List of workspace IDs to move
139 |
140 | **Used by:**
141 | - `move_workspaces_to_project` tool function to validate move parameters
142 |
143 | ## API Response Structure
144 |
145 | ### Project Details Response
146 |
147 | ```json
148 | {
149 | "data": {
150 | "id": "prj-AbCdEfGhIjKlMnOp",
151 | "type": "projects",
152 | "attributes": {
153 | "name": "Production Infrastructure",
154 | "description": "Production environment resources",
155 | "auto-destroy-activity-duration": "14d",
156 | "created-at": "2023-05-15T10:30:00Z",
157 | "permissions": {
158 | "can-destroy": true,
159 | "can-update": true,
160 | "can-access-settings": true,
161 | "can-create-workspace": true,
162 | "can-move-workspaces": true
163 | }
164 | },
165 | "relationships": {
166 | "organization": {
167 | "data": {
168 | "id": "org-AbCdEfGh",
169 | "type": "organizations"
170 | }
171 | }
172 | }
173 | }
174 | }
175 | ```
176 |
177 | ### Tag Bindings Response
178 |
179 | ```json
180 | {
181 | "data": [
182 | {
183 | "id": "tag-AbCdEfGh",
184 | "type": "tag-bindings",
185 | "attributes": {
186 | "key": "environment",
187 | "value": "production",
188 | "created-at": "2023-05-15T10:35:00Z"
189 | }
190 | },
191 | {
192 | "id": "tag-IjKlMnOp",
193 | "type": "tag-bindings",
194 | "attributes": {
195 | "key": "team",
196 | "value": "platform",
197 | "created-at": "2023-05-15T10:35:00Z"
198 | }
199 | }
200 | ]
201 | }
202 | ```
203 |
204 | ### List Projects Response
205 |
206 | ```json
207 | {
208 | "data": [
209 | {
210 | "id": "prj-AbCdEfGh",
211 | "type": "projects",
212 | "attributes": {
213 | "name": "Production",
214 | "description": "Production infrastructure",
215 | "created-at": "2023-05-15T10:30:00Z",
216 | "workspaces-count": 12
217 | }
218 | },
219 | {
220 | "id": "prj-IjKlMnOp",
221 | "type": "projects",
222 | "attributes": {
223 | "name": "Development",
224 | "description": "Development infrastructure",
225 | "created-at": "2023-05-16T14:20:00Z",
226 | "workspaces-count": 8
227 | }
228 | }
229 | ],
230 | "meta": {
231 | "pagination": {
232 | "current-page": 1,
233 | "page-size": 20,
234 | "prev-page": null,
235 | "next-page": null,
236 | "total-pages": 1,
237 | "total-count": 2
238 | }
239 | }
240 | }
241 | ```
242 |
243 | ## Related Resources
244 |
245 | - [Project Tools](../tools/project.md)
246 | - [Organization Models](organization.md)
247 | - [Workspace Models](workspace.md)
248 | - [Terraform Cloud API - Projects](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects)
```
--------------------------------------------------------------------------------
/terraform_cloud_mcp/models/state_versions.py:
--------------------------------------------------------------------------------
```python
1 | """State version models for Terraform Cloud API
2 |
3 | This module contains models for Terraform Cloud state version-related requests.
4 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions
5 | """
6 |
7 | from enum import Enum
8 | from typing import Optional
9 |
10 | from pydantic import Field
11 |
12 | from .base import APIRequest
13 |
14 |
15 | class StateVersionStatus(str, Enum):
16 | """Status options for state versions in Terraform Cloud.
17 |
18 | Defines the various states a state version can be in during its lifecycle:
19 | - PENDING: State version has been created but state data is not encoded within the request
20 | - FINALIZED: State version has been successfully uploaded or created with valid state attribute
21 | - DISCARDED: State version was discarded because it was superseded by a newer version
22 | - BACKING_DATA_SOFT_DELETED: Enterprise only - backing files are marked for garbage collection
23 | - BACKING_DATA_PERMANENTLY_DELETED: Enterprise only - backing files have been permanently deleted
24 |
25 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions#state-version-status
26 |
27 | See:
28 | docs/models/state_versions.md for reference
29 | """
30 |
31 | PENDING = "pending"
32 | FINALIZED = "finalized"
33 | DISCARDED = "discarded"
34 | BACKING_DATA_SOFT_DELETED = "backing_data_soft_deleted"
35 | BACKING_DATA_PERMANENTLY_DELETED = "backing_data_permanently_deleted"
36 |
37 |
38 | class StateVersionListRequest(APIRequest):
39 | """Request parameters for listing state versions.
40 |
41 | Defines the parameters for the state version listing API including pagination
42 | and filtering options.
43 |
44 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions#list-state-versions
45 |
46 | See:
47 | docs/models/state_versions.md for reference
48 | """
49 |
50 | filter_workspace_name: Optional[str] = Field(
51 | None,
52 | description="Filter by workspace name",
53 | )
54 | filter_organization_name: Optional[str] = Field(
55 | None,
56 | description="Filter by organization name",
57 | )
58 | filter_status: Optional[StateVersionStatus] = Field(
59 | None,
60 | description="Filter state versions by status",
61 | )
62 | page_number: Optional[int] = Field(
63 | 1,
64 | ge=1,
65 | description="Page number to fetch",
66 | )
67 | page_size: Optional[int] = Field(
68 | 20,
69 | ge=1,
70 | le=100,
71 | description="Number of results per page",
72 | )
73 |
74 |
75 | class StateVersionRequest(APIRequest):
76 | """Request model for retrieving a state version.
77 |
78 | Used to validate the state version ID parameter for API requests.
79 |
80 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions
81 |
82 | See:
83 | docs/models/state_versions.md for reference
84 | """
85 |
86 | state_version_id: str = Field(
87 | ...,
88 | description="The ID of the state version to retrieve",
89 | pattern=r"^sv-[a-zA-Z0-9]{16}$", # Standard state version ID pattern
90 | )
91 |
92 |
93 | class CurrentStateVersionRequest(APIRequest):
94 | """Request model for retrieving a workspace's current state version.
95 |
96 | Used to validate the workspace ID parameter for current state version API requests.
97 |
98 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions#get-current-state-version
99 |
100 | See:
101 | docs/models/state_versions.md for reference
102 | """
103 |
104 | workspace_id: str = Field(
105 | ...,
106 | description="The ID of the workspace to retrieve the current state version for",
107 | pattern=r"^ws-[a-zA-Z0-9]{16}$", # Standard workspace ID pattern
108 | )
109 |
110 |
111 | class StateVersionCreateRequest(APIRequest):
112 | """Request model for creating a state version.
113 |
114 | Validates and structures the request according to the Terraform Cloud API
115 | requirements for creating state versions.
116 |
117 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions#create-a-state-version
118 |
119 | See:
120 | docs/models/state_versions.md for reference
121 | """
122 |
123 | workspace_id: str = Field(
124 | ...,
125 | description="The ID of the workspace to create a state version in",
126 | pattern=r"^ws-[a-zA-Z0-9]{16}$", # Standard workspace ID pattern
127 | )
128 | serial: int = Field(
129 | ...,
130 | description="The serial of the state version",
131 | ge=0,
132 | )
133 | md5: str = Field(
134 | ...,
135 | description="An MD5 hash of the raw state version",
136 | pattern=r"^[a-fA-F0-9]{32}$", # MD5 hash pattern
137 | )
138 | state: Optional[str] = Field(
139 | None,
140 | description="Base64 encoded raw state file",
141 | )
142 | lineage: Optional[str] = Field(
143 | None,
144 | description="Lineage of the state version",
145 | )
146 | json_state: Optional[str] = Field(
147 | None,
148 | alias="json-state",
149 | description='Base64 encoded json state, as expressed by "terraform show -json"',
150 | )
151 | json_state_outputs: Optional[str] = Field(
152 | None,
153 | alias="json-state-outputs",
154 | description='Base64 encoded output values as represented by "terraform show -json"',
155 | )
156 | run_id: Optional[str] = Field(
157 | None,
158 | description="The ID of the run to associate with the state version",
159 | pattern=r"^run-[a-zA-Z0-9]{16}$", # Standard run ID pattern
160 | )
161 |
162 |
163 | class StateVersionParams(APIRequest):
164 | """Parameters for state version operations without routing fields.
165 |
166 | This model provides all optional parameters for creating state versions,
167 | reusing field definitions from StateVersionCreateRequest. It separates configuration
168 | parameters from routing information.
169 |
170 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions
171 |
172 | See:
173 | docs/models/state_versions.md for reference
174 | """
175 |
176 | serial: Optional[int] = Field(
177 | None,
178 | description="The serial of the state version",
179 | ge=0,
180 | )
181 | md5: Optional[str] = Field(
182 | None,
183 | description="An MD5 hash of the raw state version",
184 | pattern=r"^[a-fA-F0-9]{32}$", # MD5 hash pattern
185 | )
186 | state: Optional[str] = Field(
187 | None,
188 | description="Base64 encoded raw state file",
189 | )
190 | lineage: Optional[str] = Field(
191 | None,
192 | description="Lineage of the state version",
193 | )
194 | json_state: Optional[str] = Field(
195 | None,
196 | alias="json-state",
197 | description='Base64 encoded json state, as expressed by "terraform show -json"',
198 | )
199 | json_state_outputs: Optional[str] = Field(
200 | None,
201 | alias="json-state-outputs",
202 | description='Base64 encoded output values as represented by "terraform show -json"',
203 | )
204 | run_id: Optional[str] = Field(
205 | None,
206 | description="The ID of the run to associate with the state version",
207 | pattern=r"^run-[a-zA-Z0-9]{16}$", # Standard run ID pattern
208 | )
209 |
210 |
211 | # Response handling is implemented through raw dictionaries
212 |
```
--------------------------------------------------------------------------------
/docs/conversations/cost-estimate-conversation.md:
--------------------------------------------------------------------------------
```markdown
1 | # Cost Estimate Management Conversation
2 |
3 | This file demonstrates Claude's ability to interact with the Terraform Cloud MCP to retrieve and analyze cost estimate information.
4 |
5 | ## Getting a Cost Estimate by ID
6 |
7 | ```
8 | **User:** Can you check the cost estimate for my latest infrastructure changes? The cost estimate ID is ce-BPvFFrYCqRV6qVBK.
9 |
10 | **Claude:** I'll retrieve the cost estimate details for you right away.
11 |
12 | [Claude uses get_cost_estimate_details tool]
13 |
14 | Here's the summary of your cost estimate:
15 |
16 | - **Status**: Finished
17 | - **Prior Monthly Cost**: $0.00
18 | - **Proposed Monthly Cost**: $25.49
19 | - **Change in Monthly Cost**: +$25.49 (100% increase)
20 | - **Resources Analyzed**: 4 total (3 matched, 1 unmatched)
21 |
22 | The estimate shows that your infrastructure changes will add approximately $25.49 to your monthly costs. This is from new resources being added since your prior cost was $0.00.
23 | ```
24 |
25 | ## Finding a Cost Estimate from a Run
26 |
27 | ```
28 | **User:** How do I find the cost estimate for a specific run? I have run ID run-pQtfN5XSe8zaJ2UF.
29 |
30 | **Claude:** I'll show you how to find the cost estimate for your specific run ID.
31 |
32 | [Claude uses get_run_details tool to retrieve run information]
33 |
34 | I can see from the run details that there's a cost estimate associated with this run. Let me get the detailed cost information for you.
35 |
36 | [Claude uses get_cost_estimate_details tool]
37 |
38 | I found the cost estimate for your run. Here are the details:
39 |
40 | - **Cost Estimate ID**: ce-8cZKNpyP3R2fBaXD
41 | - **Status**: Finished
42 | - **Prior Monthly Cost**: $127.32
43 | - **Proposed Monthly Cost**: $158.76
44 | - **Change in Monthly Cost**: +$31.44 (24.7% increase)
45 | - **Resources Analyzed**: 18 total (16 matched, 2 unmatched)
46 |
47 | Your run will increase costs by $31.44 per month. The two unmatched resources are likely new resources being added that don't have previous cost data.
48 | ```
49 |
50 | ## Understanding Cost Estimate Error
51 |
52 | ```
53 | **User:** I tried to look at a cost estimate but got an error. The ID was ce-ZXcY12AbPq9LkMnR.
54 |
55 | **Claude:** Let me check what might be causing the error with that cost estimate ID.
56 |
57 | [Claude uses get_cost_estimate_details tool]
58 |
59 | I checked the cost estimate with ID ce-ZXcY12AbPq9LkMnR and found the following issue:
60 |
61 | The cost estimate appears to have an error status. Here are the details:
62 |
63 | - **Status**: Errored
64 | - **Error Message**: "Failed to calculate costs: Provider AWS returned error: Resource pricing data unavailable for region eu-west-3"
65 | - **Timestamp**: Started at 2023-06-15T14:23:18Z, errored at 2023-06-15T14:23:45Z
66 |
67 | This error is occurring because the cost estimation service doesn't have pricing data for resources in the eu-west-3 AWS region. This typically happens when:
68 |
69 | 1. You're using a newer AWS region that isn't fully integrated with the Terraform Cloud cost estimation service yet
70 | 2. You're using resources that don't have standard pricing data available
71 |
72 | Options to resolve this:
73 | 1. Consider using an AWS region that has full cost estimation support, like us-east-1, us-west-2, or eu-west-1
74 | 2. You can still proceed with your infrastructure changes, but you won't get accurate cost estimates
75 | 3. Contact Terraform Cloud support if you need cost estimation support for this specific region
76 | ```
77 |
78 | ## Comparing Multiple Cost Estimates
79 |
80 | ```
81 | **User:** I want to compare the cost estimates from my last two runs to see which one is more cost-effective.
82 |
83 | **Claude:** I'll help you compare the cost estimates from your last two runs.
84 |
85 | [Claude uses get_run_details tool for each run to extract cost estimate IDs]
86 |
87 | [Claude uses get_cost_estimate_details tool for each cost estimate]
88 |
89 | Here's a comparison of the cost estimates from your last two runs:
90 |
91 | | Run | Message | Prior Cost | Proposed Cost | Change | Resources |
92 | |-----|---------|------------|---------------|--------|-----------|
93 | | run-pQtfN5XSe8zaJ2UF | Add Redis cluster | $127.32 | $158.76 | +$31.44 | 18 |
94 | | run-aB3cD4eF5gH6iJ7k | Optimize compute resources | $158.76 | $142.18 | -$16.58 | 18 |
95 |
96 | Based on this comparison:
97 |
98 | 1. The first run adds a Redis cluster, increasing your monthly costs by $31.44
99 | 2. The second run optimizes your compute resources, decreasing your monthly costs by $16.58
100 |
101 | The second run is more cost-effective, saving you $16.58 per month compared to the first run. However, note that the runs have different purposes - one adds functionality while the other optimizes costs. The most cost-effective choice depends on whether you need the Redis cluster functionality.
102 | ```
103 |
104 | ```
105 | **User:** That's helpful! How can I get more detailed information about which resources contribute the most to my costs?
106 |
107 | **Claude:** To get more detailed information about which resources contribute most to your costs, I'll analyze the detailed breakdown from your cost estimate.
108 |
109 | [Claude uses get_cost_estimate_details tool to retrieve detailed resource cost information]
110 |
111 | Based on the analysis of your cost estimate, here are the key insights:
112 |
113 | ### Top Resource Types by Cost
114 | 1. **aws_instance**: $72.34/month (45.6% of total costs)
115 | 2. **aws_rds_cluster**: $45.60/month (28.7% of total costs)
116 | 3. **aws_elasticache_cluster**: $31.44/month (19.8% of total costs)
117 | 4. **aws_s3_bucket**: $5.62/month (3.5% of total costs)
118 | 5. **aws_ebs_volume**: $3.76/month (2.4% of total costs)
119 |
120 | ### Top Individual Resources
121 | 1. **aws_rds_cluster.primary**: $45.60/month
122 | - Main database cluster
123 | - Components: Instance costs, storage costs, backup costs
124 |
125 | 2. **aws_instance.web_servers[4]**: $14.47/month
126 | - Web server instance #4 (t3.large)
127 | - Components: Compute hours, storage
128 |
129 | 3. **aws_instance.web_servers[3]**: $14.47/month
130 | - Web server instance #3 (t3.large)
131 | - Components: Compute hours, storage
132 |
133 | 4. **aws_elasticache_cluster.redis_primary**: $31.44/month
134 | - Redis cluster (cache.m5.large)
135 | - Components: Node hours, memory allocation
136 |
137 | 5. **aws_instance.application_server**: $14.60/month
138 | - Application server (t3.large)
139 | - Components: Compute hours, storage
140 |
141 | ### Cost Optimization Recommendations
142 |
143 | Based on this cost breakdown, here are some opportunities to reduce costs:
144 |
145 | 1. **Right-size your instances**: Some of your web servers might be over-provisioned. Consider using t3.medium instead of t3.large for less critical workloads.
146 |
147 | 2. **Use reserved instances**: Your EC2 instances account for nearly half of your costs. Consider purchasing reserved instances for stable workloads to save 30-60% on your EC2 costs.
148 |
149 | 3. **Optimize your Redis usage**: Your Redis cluster represents a significant cost. Consider whether you need the current size or if a smaller instance would suffice.
150 |
151 | 4. **Review your RDS cluster**: Your RDS cluster is your second-highest cost. Review if you need all the provisioned resources or if you could use a smaller instance type.
152 |
153 | 5. **S3 lifecycle policies**: For your S3 buckets, implement lifecycle policies to transition infrequently accessed data to cheaper storage classes.
154 |
155 | Would you like me to dive deeper into any specific resource to find more cost-saving opportunities?
156 | ```
```
--------------------------------------------------------------------------------
/docs/conversations/plan-management-conversation.md:
--------------------------------------------------------------------------------
```markdown
1 | # Plan Management Conversation Examples
2 |
3 | This document provides example conversations demonstrating how to use the plan management tools in the Terraform Cloud MCP.
4 |
5 | ## Getting Plan Details
6 |
7 | ```
8 | **User:** I'd like to see details for my plan with ID plan-aBcdEfGh12345678
9 |
10 | **Claude:** I'll retrieve the details for that plan for you.
11 |
12 | [Claude uses get_plan_details tool]
13 |
14 | Here are the details for plan-aBcdEfGh12345678:
15 |
16 | Status: finished
17 | Resources to add: 3
18 | Resources to change: 1
19 | Resources to destroy: 0
20 |
21 | The plan was queued at 2025-02-15T14:30:22Z, started at 2025-02-15T14:31:05Z, and finished at 2025-02-15T14:32:18Z.
22 |
23 | It's associated with run-pQrStUvW12345678 in workspace "production-infrastructure".
24 | ```
25 |
26 | ## Retrieving Plan Logs
27 |
28 | ```
29 | **User:** Can you show me the actual Terraform plan output for plan-aBcdEfGh12345678?
30 |
31 | **Claude:** I'll retrieve the plan logs for you.
32 |
33 | [Claude uses get_plan_logs tool]
34 |
35 | I've retrieved the complete plan execution logs. The plan shows that Terraform will create an S3 bucket called "example-data-bucket" with versioning enabled and production tags, create a new IAM role for Lambda execution, and modify an existing security group to add an HTTPS ingress rule allowing traffic from anywhere.
36 |
37 | The plan execution used Terraform v1.5.7 and successfully determined that 2 resources will be added and 1 will be changed, with no resources being destroyed.
38 |
39 | Would you like me to explain any part of this plan in more detail?
40 | ```
41 |
42 | ## Retrieving Plan JSON Output
43 |
44 | ```
45 | **User:** Can you get me the JSON execution output for plan-aBcdEfGh12345678? I need to analyze the changes.
46 |
47 | **Claude:** I'll retrieve the JSON execution plan for you.
48 |
49 | [Claude uses get_plan_json_output tool]
50 |
51 | I've obtained the JSON execution plan. Here's an analysis of the planned changes:
52 |
53 | The plan includes:
54 | - 2 resources to be created (aws_s3_bucket.data and aws_iam_role.lambda_role)
55 | - 1 resource to be modified (aws_security_group.allow_http)
56 | - 0 resources to be destroyed
57 |
58 | Key modifications:
59 | - The security group is having a new ingress rule added for HTTPS (port 443)
60 | - The new S3 bucket will have versioning enabled
61 | - The IAM role has permissions for Lambda and S3 access
62 |
63 | The plan was generated with Terraform 1.5.7 and includes all configuration details and state information. Would you like me to extract any specific part of the plan for more detailed analysis?
64 | ```
65 |
66 | ## Retrieving Run Plan JSON Output
67 |
68 | ```
69 | **User:** I'm working with a run ID run-xYzAbCdE12345678 and need the JSON execution plan from that run.
70 |
71 | **Claude:** I'll get the JSON plan output from that run for you.
72 |
73 | [Claude uses get_run_plan_json_output tool]
74 |
75 | I've retrieved the JSON execution plan for run-xYzAbCdE12345678. This is a destruction plan that will remove the following resources:
76 |
77 | - aws_instance.web_server (EC2 instance)
78 | - aws_security_group.web_access
79 | - aws_s3_bucket.logs
80 | - aws_cloudwatch_metric_alarm.high_cpu
81 |
82 | The plan was generated with Terraform version 1.6.2. All four resources will be completely removed, and the state will be updated accordingly.
83 |
84 | The plan shows that this will remove:
85 | - 1 EC2 t2.micro instance in us-west-2
86 | - 1 security group with 3 ingress rules
87 | - 1 S3 bucket containing approximately 250MB of log data
88 | - 1 CloudWatch alarm that was monitoring the EC2 instance
89 |
90 | Would you like me to extract any specific details from the plan?
91 | ```
92 |
93 | ## Working with Plan Status
94 |
95 | ```
96 | **User:** My plan seems to be taking a long time. The ID is plan-mNoPqRsT12345678. What's its status?
97 |
98 | **Claude:** Let me check the status of that plan for you.
99 |
100 | [Claude uses get_plan_details tool]
101 |
102 | Your plan with ID plan-mNoPqRsT12345678 is currently in the "running" status.
103 |
104 | It was queued at 2025-03-01T09:15:33Z and started execution at 2025-03-01T09:16:10Z (about 25 minutes ago).
105 |
106 | This plan is running in an agent execution mode on agent "prod-deployment-agent-05" in the "Production" agent pool. Complex plans with many resources can take time to complete, especially if there are many computed values or external data sources.
107 |
108 | Would you like me to check if there are any logs available that might provide more information about the progress?
109 | ```
110 |
111 | ## Analyzing Plan Resources
112 |
113 | ```
114 | **User:** I need to understand what resources will be created in plan-gHiJkLmN12345678
115 |
116 | **Claude:** I'll retrieve and analyze the plan details for you.
117 |
118 | [Claude uses get_plan_details tool]
119 |
120 | The plan plan-gHiJkLmN12345678 will create 5 new resources:
121 |
122 | - 2 aws_security_group resources
123 | - 1 aws_instance (EC2) resource
124 | - 1 aws_s3_bucket resource
125 | - 1 aws_iam_role resource
126 |
127 | The plan will also modify 2 existing resources and destroy 1 resource.
128 |
129 | This plan was created as part of run-eFgHiJkL12345678 in workspace "network-infrastructure" and has already finished execution. It's ready to be applied.
130 |
131 | For more detailed analysis of the exact resource configurations, I can retrieve the JSON execution plan which contains the full definition of all resource changes.
132 | ```
133 |
134 | ## Comparing Multiple Plans
135 |
136 | ```
137 | **User:** I have two plans I want to compare: plan-qRsTuVwX12345678 and plan-yZaBcDeF12345678
138 |
139 | **Claude:** I'll retrieve both plans and compare them for you.
140 |
141 | [Claude uses get_plan_details tool]
142 |
143 | Here's a comparison of the two plans:
144 |
145 | Plan 1 (plan-qRsTuVwX12345678):
146 | - Status: finished
147 | - Resources to add: 4
148 | - Resources to change: 2
149 | - Resources to destroy: 1
150 | - Execution time: 1m 45s (2025-03-10)
151 | - Run: run-aBcDeFgH12345678
152 |
153 | Plan 2 (plan-yZaBcDeF12345678):
154 | - Status: finished
155 | - Resources to add: 4
156 | - Resources to change: 3
157 | - Resources to destroy: 0
158 | - Execution time: 2m 12s (2025-03-15)
159 | - Run: run-iJkLmNoP12345678
160 |
161 | The second plan (from March 15) modifies one additional resource compared to the first plan (from March 10), but doesn't destroy any resources. Both plans add the same number of new resources.
162 |
163 | To see exactly what changed between these plans, I can retrieve and compare the JSON output for both.
164 | ```
165 |
166 | ## Examining Plan Logs for Errors
167 |
168 | ```
169 | **User:** I'm concerned about potential issues in plan-kLmNoPqR12345678. Can you check the logs for any warnings or errors?
170 |
171 | **Claude:** I'll examine the plan logs for warnings or errors.
172 |
173 | [Claude uses get_plan_logs tool]
174 |
175 | I've analyzed the plan logs and found the following issues:
176 |
177 | Warnings:
178 | 1. Deprecated attribute: The plan contains a warning about using the deprecated "public_ip" attribute on aws_instance.web. The recommended replacement is "public_ip_address".
179 |
180 | 2. Provider version constraint: There's a warning that the azurerm provider being used (3.0.1) is older than the recommended minimum version (3.2.0).
181 |
182 | Potential errors:
183 | 1. Data source dependency: The plan shows that aws_vpc.main will be created before aws_subnet.primary, but there's a reference to the VPC ID in the subnet. This could cause issues if the VPC creation fails.
184 |
185 | 2. Resource validation warning: An S3 bucket name "my-bucket" might not be globally unique, which could cause the apply to fail.
186 |
187 | The plan itself completed successfully but these issues might cause problems during apply. Would you like me to give recommendations on how to address these concerns?
188 | ```
```
--------------------------------------------------------------------------------
/terraform_cloud_mcp/models/projects.py:
--------------------------------------------------------------------------------
```python
1 | """Project models for Terraform Cloud API
2 |
3 | This module contains models for Terraform Cloud project-related requests.
4 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects
5 | """
6 |
7 | from typing import List, Optional
8 |
9 | from pydantic import Field
10 |
11 | from .base import APIRequest
12 |
13 |
14 | class TagBinding(APIRequest):
15 | """Tag binding configuration for a project.
16 |
17 | Defines a tag key-value pair that can be bound to a project
18 | and inherited by its workspaces.
19 |
20 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects
21 |
22 | See:
23 | docs/models/project.md for reference
24 | """
25 |
26 | # Inherits model_config from APIRequest -> BaseModelConfig
27 |
28 | key: str = Field(..., description="The key of the tag")
29 | value: str = Field(..., description="The value of the tag")
30 |
31 |
32 | class ProjectListRequest(APIRequest):
33 | """Request parameters for listing projects in an organization.
34 |
35 | Defines the parameters for the project listing API including pagination
36 | and search filtering options.
37 |
38 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects#list-projects
39 |
40 | See:
41 | docs/models/project.md for reference
42 | """
43 |
44 | organization: str = Field(
45 | ...,
46 | description="The name of the organization to list projects from",
47 | min_length=3,
48 | pattern=r"^[a-z0-9][-a-z0-9_]*[a-z0-9]$",
49 | )
50 | page_number: Optional[int] = Field(1, ge=1, description="Page number to fetch")
51 | page_size: Optional[int] = Field(
52 | 20, ge=1, le=100, description="Number of results per page"
53 | )
54 | q: Optional[str] = Field(None, description="Search query for name")
55 | filter_names: Optional[str] = Field(
56 | None, description="Filter projects by name (comma-separated)"
57 | )
58 | filter_permissions_update: Optional[bool] = Field(
59 | None, description="Filter projects by update permission"
60 | )
61 | filter_permissions_create_workspace: Optional[bool] = Field(
62 | None, description="Filter projects by create workspace permission"
63 | )
64 | sort: Optional[str] = Field(
65 | None, description="Sort projects by name ('name' or '-name' for descending)"
66 | )
67 |
68 |
69 | class BaseProjectRequest(APIRequest):
70 | """Base class for project create and update requests with common fields.
71 |
72 | This includes common fields used in request payloads for project
73 | creation and update APIs, providing a foundation for more specific project models.
74 |
75 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects
76 |
77 | Note:
78 | This class inherits model_config from APIRequest -> BaseModelConfig and provides
79 | default values for fields based on Terraform Cloud API defaults.
80 |
81 | See:
82 | docs/models/project.md for detailed field descriptions and usage examples
83 | """
84 |
85 | # Fields common to both create and update requests
86 | name: Optional[str] = Field(
87 | None,
88 | description="Name of the project",
89 | )
90 | description: Optional[str] = Field(
91 | None,
92 | description="Description of the project",
93 | )
94 | auto_destroy_activity_duration: Optional[str] = Field(
95 | None,
96 | alias="auto-destroy-activity-duration",
97 | description="How long each workspace should wait before auto-destroying (e.g., '14d', '24h')",
98 | )
99 | tag_bindings: Optional[List[TagBinding]] = Field(
100 | None,
101 | alias="tag-bindings",
102 | description="Tags to bind to the project, inherited by workspaces",
103 | )
104 |
105 |
106 | class ProjectCreateRequest(BaseProjectRequest):
107 | """Request model for creating a Terraform Cloud project.
108 |
109 | Validates and structures the request according to the Terraform Cloud API
110 | requirements for creating projects. Extends BaseProjectRequest with
111 | required fields for creation.
112 |
113 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects#create-a-project
114 |
115 | Note:
116 | This inherits all configuration fields from BaseProjectRequest
117 | while making organization and name required.
118 |
119 | See:
120 | docs/models/project.md for reference
121 | """
122 |
123 | # Organization is needed for routing but not included in the payload
124 | organization: str = Field(
125 | ...,
126 | description="The name of the organization to create the project in",
127 | )
128 |
129 | # Override name to make it required for creation
130 | name: str = Field(
131 | ...,
132 | description="Name of the project",
133 | )
134 |
135 |
136 | class ProjectUpdateRequest(BaseProjectRequest):
137 | """Request model for updating a Terraform Cloud project.
138 |
139 | Validates and structures the request for updating projects. Extends BaseProjectRequest
140 | with routing fields while keeping all configuration fields optional.
141 |
142 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects#update-a-project
143 |
144 | Note:
145 | This inherits all configuration fields from BaseProjectRequest
146 | and adds required routing field for the update operation.
147 |
148 | See:
149 | docs/models/project.md for reference
150 | """
151 |
152 | # Add project_id which is required for updates but not part of the project attributes payload
153 | project_id: str = Field(
154 | ...,
155 | description="The ID of the project to update",
156 | )
157 |
158 |
159 | class ProjectParams(BaseProjectRequest):
160 | """Parameters for project operations without routing fields.
161 |
162 | This model provides all optional parameters for creating or updating projects,
163 | reusing field definitions from BaseProjectRequest. It separates configuration
164 | parameters from routing information like organization and project ID.
165 |
166 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects
167 |
168 | Note:
169 | When updating a project, use this model to specify only the attributes
170 | you want to change. Unspecified attributes retain their current values.
171 | All fields are inherited from BaseProjectRequest.
172 |
173 | See:
174 | docs/models/project.md for reference
175 | """
176 |
177 | # Inherits model_config and all fields from BaseProjectRequest
178 |
179 |
180 | class ProjectTagBindingRequest(APIRequest):
181 | """Request model for adding or updating tag bindings on a project.
182 |
183 | This model is used for the PATCH /projects/{project_id}/tag-bindings endpoint,
184 | which allows adding or updating tag bindings on an existing project.
185 |
186 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects#add-or-update-tag-bindings-on-a-project
187 |
188 | See:
189 | docs/models/project.md for reference
190 | """
191 |
192 | project_id: str = Field(
193 | ...,
194 | description="The ID of the project to update tag bindings for",
195 | )
196 | tag_bindings: List[TagBinding] = Field(
197 | ...,
198 | description="Tags to bind to the project",
199 | )
200 |
201 |
202 | class WorkspaceMoveRequest(APIRequest):
203 | """Request model for moving workspaces into a project.
204 |
205 | This model is used for the POST /projects/{project_id}/relationships/workspaces endpoint,
206 | which allows moving one or more workspaces into a project.
207 |
208 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects#move-workspaces-into-a-project
209 |
210 | See:
211 | docs/models/project.md for reference
212 | """
213 |
214 | project_id: str = Field(
215 | ...,
216 | description="The ID of the destination project",
217 | )
218 | workspace_ids: List[str] = Field(
219 | ...,
220 | description="The IDs of workspaces to move into the project",
221 | )
222 |
```
--------------------------------------------------------------------------------
/docs/tools/workspace.md:
--------------------------------------------------------------------------------
```markdown
1 | # Workspace Tools
2 |
3 | This module provides tools for managing workspaces in Terraform Cloud.
4 |
5 | ## Overview
6 |
7 | Workspaces in Terraform Cloud are isolated environments for managing infrastructure, containing Terraform configurations, state files, variables, and run histories. These tools allow you to create, read, update, delete, lock, and unlock workspaces.
8 |
9 | ## API Reference
10 |
11 | These tools interact with the Terraform Cloud Workspaces API:
12 | - [Workspaces API Documentation](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces)
13 | - [Workspace Settings](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/settings)
14 |
15 | ## Tools Reference
16 |
17 | ### list_workspaces
18 |
19 | **Function:** `list_workspaces(organization: str, page_number: int = 1, page_size: int = 20, search: Optional[str] = None) -> Dict[str, Any]`
20 |
21 | **Description:** Retrieves a paginated list of all workspaces in an organization.
22 |
23 | **Parameters:**
24 | - `organization` (str): The name of the organization to list workspaces from
25 | - `page_number` (int, optional): The page number to return (default: 1)
26 | - `page_size` (int, optional): Number of items per page (default: 20, max: 100)
27 | - `search` (str, optional): Filter workspaces by name
28 |
29 | **Returns:** JSON response containing paginated list of workspaces with their configuration and metadata.
30 |
31 | **Notes:**
32 | - Requires "read workspaces" permission on the organization
33 | - Use the search parameter to find workspaces by partial name match
34 | - Results are paginated, with metadata indicating total count and links to additional pages
35 |
36 | ### get_workspace_details
37 |
38 | **Function:** `get_workspace_details(workspace_id: str = "", organization: str = "", workspace_name: str = "") -> Dict[str, Any]`
39 |
40 | **Description:** Gets detailed information about a specific workspace, identified by ID or by organization and workspace name.
41 |
42 | **Parameters:**
43 | - `workspace_id` (str, optional): The ID of the workspace (format: "ws-xxxxxxxx")
44 | - `organization` (str, optional): The organization name (required if workspace_id not provided)
45 | - `workspace_name` (str, optional): The workspace name (required if workspace_id not provided)
46 |
47 | **Returns:** JSON response with comprehensive workspace details including configuration and current status.
48 |
49 | **Notes:**
50 | - You can identify the workspace either by ID directly, or by organization+name combination
51 | - Requires "read workspaces" permission on the organization or workspace
52 |
53 | ### create_workspace
54 |
55 | **Function:** `create_workspace(organization: str, name: str, params: Optional[WorkspaceParams] = None) -> Dict[str, Any]`
56 |
57 | **Description:** Creates a new workspace in the specified organization.
58 |
59 | **Parameters:**
60 | - `organization` (str): The organization name
61 | - `name` (str): The name for the new workspace
62 | - `params` (WorkspaceParams, optional): Additional configuration options:
63 | - `description`: Human-readable description
64 | - `execution_mode`: How operations are executed (remote, local, agent)
65 | - `terraform_version`: Version of Terraform to use
66 | - `working_directory`: Subdirectory for Terraform configuration
67 | - `vcs_repo`: Version control repository configuration
68 | - `auto_apply`: Whether to auto-apply successful plans
69 | - And many other options...
70 |
71 | **Returns:** JSON response with the created workspace details.
72 |
73 | **Notes:**
74 | - Requires "create workspaces" permission on the organization
75 | - Workspace names must be unique within an organization
76 | - Default execution mode is "remote" unless otherwise specified
77 |
78 | ### update_workspace
79 |
80 | **Function:** `update_workspace(organization: str, workspace_name: str, params: Optional[WorkspaceParams] = None) -> Dict[str, Any]`
81 |
82 | **Description:** Updates an existing workspace's settings.
83 |
84 | **Parameters:**
85 | - `organization` (str): The organization name
86 | - `workspace_name` (str): The current workspace name
87 | - `params` (WorkspaceParams, optional): Settings to update, including:
88 | - `name`: New name for the workspace (if renaming)
89 | - `description`: Human-readable description
90 | - And all other options available in create_workspace...
91 |
92 | **Returns:** JSON response with the updated workspace details.
93 |
94 | **Notes:**
95 | - Requires "update workspace settings" permission
96 | - Only specified attributes will be updated; unspecified attributes remain unchanged
97 | - To rename a workspace, include the new name in the params
98 |
99 | ### delete_workspace
100 |
101 | **Function:** `delete_workspace(organization: str, workspace_name: str) -> Dict[str, Any]`
102 |
103 | **Description:** Permanently deletes a workspace and all related resources.
104 |
105 | **Parameters:**
106 | - `organization` (str): The organization name
107 | - `workspace_name` (str): The workspace name to delete
108 |
109 | **Returns:** Success message with no content (HTTP 204) if successful.
110 |
111 | **Notes:**
112 | - Requires "delete workspaces" permission
113 | - This is a destructive operation that cannot be undone
114 | - Will delete all state versions, run history, and configuration versions
115 | - Use safe_delete_workspace if you want to check for resources first
116 |
117 | ### safe_delete_workspace
118 |
119 | **Function:** `safe_delete_workspace(organization: str, workspace_name: str) -> Dict[str, Any]`
120 |
121 | **Description:** Safely deletes a workspace after checking if it has resources.
122 |
123 | **Parameters:**
124 | - `organization` (str): The organization name
125 | - `workspace_name` (str): The workspace name to delete
126 |
127 | **Returns:** Success message or error if the workspace has resources.
128 |
129 | **Notes:**
130 | - Requires "delete workspaces" permission
131 | - Prevents accidental deletion of workspaces with active infrastructure
132 | - Will fail if the workspace has any resources
133 |
134 | ### lock_workspace
135 |
136 | **Function:** `lock_workspace(workspace_id: str, reason: str = "") -> Dict[str, Any]`
137 |
138 | **Description:** Locks a workspace to prevent runs from being queued.
139 |
140 | **Parameters:**
141 | - `workspace_id` (str): The ID of the workspace to lock
142 | - `reason` (str, optional): Reason for locking the workspace
143 |
144 | **Returns:** JSON response with updated workspace including lock information.
145 |
146 | **Notes:**
147 | - Requires "lock workspaces" permission
148 | - Locking prevents new runs but doesn't affect already running plans or applies
149 | - Useful during maintenance or when making manual changes
150 |
151 | ### unlock_workspace
152 |
153 | **Function:** `unlock_workspace(workspace_id: str) -> Dict[str, Any]`
154 |
155 | **Description:** Unlocks a previously locked workspace.
156 |
157 | **Parameters:**
158 | - `workspace_id` (str): The ID of the workspace to unlock
159 |
160 | **Returns:** JSON response with updated workspace showing unlocked status.
161 |
162 | **Notes:**
163 | - Requires "unlock workspaces" permission
164 | - Can only unlock workspaces that you locked (unless you have admin rights)
165 |
166 | ### force_unlock_workspace
167 |
168 | **Function:** `force_unlock_workspace(workspace_id: str) -> Dict[str, Any]`
169 |
170 | **Description:** Force unlocks a workspace even if locked by another user.
171 |
172 | **Parameters:**
173 | - `workspace_id` (str): The ID of the workspace to force unlock
174 |
175 | **Returns:** JSON response with updated workspace showing unlocked status.
176 |
177 | **Notes:**
178 | - Requires admin privileges on the workspace
179 | - Use with caution - should only be used when the normal unlock process isn't possible
180 | - Typically needed when a run has orphaned a lock or the user who locked is unavailable
181 |
182 | **Common Error Scenarios:**
183 |
184 | | Error | Cause | Solution |
185 | |-------|-------|----------|
186 | | 404 | Workspace not found | Verify the workspace ID or name exists |
187 | | 403 | Insufficient permissions | Ensure you have the proper permissions |
188 | | 422 | Validation error | Ensure workspace name follows conventions (only lowercase letters, numbers, hyphens, underscores) |
189 | | 409 | Conflict | Workspace name already exists in organization |
190 | | 423 | Workspace is locked | Unlock the workspace first or use force_unlock_workspace |
```
--------------------------------------------------------------------------------
/docs/conversations/organizations-management-conversation.md:
--------------------------------------------------------------------------------
```markdown
1 | # Organization Management - Example Conversations
2 |
3 | This document shows example conversations with Claude using the Terraform Cloud MCP organization management features.
4 |
5 | ## Listing and Finding Organizations
6 |
7 | ```
8 | **User**: List all my Terraform Cloud organizations
9 |
10 | **Claude**: I'll list all the Terraform Cloud organizations you have access to.
11 |
12 | [Claude uses list_organizations tool]
13 |
14 | Here are all the Terraform Cloud organizations you have access to:
15 |
16 | 1. **example-org**
17 | - Email: [email protected]
18 | - Created: January 15, 2023
19 | - Plan: Team & Governance
20 |
21 | 2. **terraform-demo**
22 | - Email: [email protected]
23 | - Created: March 3, 2023
24 | - Plan: Free
25 |
26 | 3. **acme-corp**
27 | - Email: [email protected]
28 | - Created: June 12, 2023
29 | - Plan: Business
30 |
31 | 4. **infrastructure-team**
32 | - Email: [email protected]
33 | - Created: August 8, 2023
34 | - Plan: Free
35 |
36 | 5. **test-org**
37 | - Email: [email protected]
38 | - Created: December 1, 2023
39 | - Plan: Free
40 | ```
41 |
42 | ```
43 | **User**: Show me details for my "example-org" organization
44 |
45 | **Claude**: I'll retrieve detailed information about the "example-org" organization.
46 |
47 | [Claude uses get_organization_details tool]
48 |
49 | Here are the details for the "example-org" organization:
50 |
51 | **Basic Information:**
52 | - Name: example-org
53 | - ID: org-WV6DfwfxxXvLfvfs
54 | - External ID: org-WV6DfwfxxXvLfvfs
55 | - Created: January 15, 2023
56 | - Email: [email protected]
57 |
58 | **Plan Details:**
59 | - Plan Type: Team & Governance
60 | - Plan Expired: No
61 | - Trial Status: Not on trial
62 | - Enterprise Plan: No
63 |
64 | **Settings:**
65 | - Default Execution Mode: Remote
66 | - Collaborator Auth Policy: Password
67 | - Cost Estimation Enabled: Yes
68 | - Run Queuing Enabled: Yes
69 | - VCS Status Updates: Aggregated (commit status enabled)
70 | - SAML Enabled: No
71 |
72 | **Permissions:**
73 | - You can manage users, teams, and workspaces
74 | - You can manage VCS connections
75 | - You can create and manage modules
76 | - You can create and manage policy sets
77 | - You can manage subscription settings
78 |
79 | This organization is on the Team & Governance tier with active cost estimation features and standard remote execution setup.
80 | ```
81 |
82 | ```
83 | **User**: Get information about "example-org" organization
84 |
85 | **Claude**: I'll retrieve the details for the "example-org" organization.
86 |
87 | [Claude uses get_organization_details tool]
88 |
89 | Here are the details for the "example-org" organization:
90 |
91 | **Basic Information:**
92 | - Name: example-org
93 | - ID: org-WV6DfwfxxXvLfvfs
94 | - External ID: org-WV6DfwfxxXvLfvfs
95 | - Created: January 15, 2023
96 | - Email: [email protected]
97 | - Plan Type: Team & Governance
98 |
99 | The organization is on the Team & Governance tier. If you'd like to see the organization's entitlements and feature limits, I can retrieve that information separately.
100 | ```
101 |
102 | ```
103 | **User**: What are the entitlements for my "example-org" organization?
104 |
105 | **Claude**: I'll specifically check the entitlements for your "example-org" organization.
106 |
107 | [Claude uses get_organization_entitlements tool]
108 |
109 | Here are the detailed entitlements for your "example-org" organization:
110 |
111 | **Features:**
112 | - Operations: Yes (remote Terraform operations)
113 | - Private Module Registry: Yes
114 | - Sentinel Policies: Yes
115 | - Teams: Yes
116 | - Cost Estimation: Yes
117 | - VCS Integrations: Yes
118 | - State Storage: Yes
119 | - Self-Serve Billing: Yes
120 | - Configuration Designer: Yes
121 | - Run Tasks: Yes
122 |
123 | **Enterprise Features (Not Available):**
124 | - SSO: No
125 | - Audit Logging: No
126 | - Agents: No
127 | - Private Policy Agents: No
128 |
129 | **Limits:**
130 | - User Limit: 25
131 | - Team Limit: Unlimited
132 | - Policy Limit: 15
133 | - Policy Set Limit: 20
134 | - Run Task Limit: 10
135 | - Run Task Workspace Limit: 100
136 | - Policy Mandatory Enforcement Limit: 5
137 |
138 | Your organization has the Team & Governance tier features, including policy as code (Sentinel), cost estimation, and team management. You don't currently have access to enterprise features like SSO or audit logging. Your organization can have up to 25 users and has reasonable limits for policies and run tasks.
139 | ```
140 |
141 | ```
142 | **User**: Find organizations with "prod" in their name
143 |
144 | **Claude**: I'll search for organizations with "prod" in their name.
145 |
146 | [Claude uses list_organizations tool with name filter]
147 |
148 | I found the following organizations with "prod" in their name:
149 |
150 | 1. **production-infra**
151 | - Email: [email protected]
152 | - Created: February 10, 2023
153 | - Plan: Business
154 |
155 | 2. **acme-prod**
156 | - Email: [email protected]
157 | - Created: July 7, 2023
158 | - Plan: Team & Governance
159 |
160 | 3. **production-systems**
161 | - Email: [email protected]
162 | - Created: October 15, 2023
163 | - Plan: Free
164 |
165 | These three organizations match your search query for "prod" in their names. Each has different plan levels and was created at different times.
166 | ```
167 |
168 | ## Creating and Managing Organizations
169 |
170 | ```
171 | **User**: Create a new organization named "terraform-demo" with my email "[email protected]"
172 |
173 | **Claude**: I'll create a new organization named "terraform-demo" with your email.
174 |
175 | [Claude uses create_organization tool]
176 |
177 | I've successfully created a new organization in Terraform Cloud. Here are the details:
178 |
179 | **Organization Created:**
180 | - Name: terraform-demo
181 | - Email: [email protected]
182 | - ID: org-Bzyc2JuegvVLAibn
183 | - Creation Date: Just now
184 |
185 | **Default Configuration:**
186 | - Execution Mode: Remote
187 | - Authentication Policy: Password
188 | - Cost Estimation: Disabled
189 | - Session Timeout: 20160 minutes (14 days)
190 |
191 | **Initial Entitlements:**
192 | - Private Module Registry: Yes
193 | - State Storage: Yes
194 | - VCS Integrations: Yes
195 | - Teams: No (Free tier)
196 | - Sentinel Policies: No (Free tier)
197 | - User Limit: 5 (Free tier)
198 |
199 | The organization has been created with default settings. You're currently the owner of this organization. You can invite additional members and create workspaces within this organization.
200 | ```
201 |
202 | ```
203 | **User**: Update my "terraform-demo" organization to enable cost estimation
204 |
205 | **Claude**: I'll update the "terraform-demo" organization to enable cost estimation.
206 |
207 | [Claude uses update_organization tool]
208 |
209 | I've updated the "terraform-demo" organization to enable cost estimation. Here's the confirmation:
210 |
211 | **Organization Updated:**
212 | - Name: terraform-demo
213 | - Email: [email protected]
214 | - ID: org-Bzyc2JuegvVLAibn
215 |
216 | **Updated Setting:**
217 | - Cost Estimation: Enabled (previously Disabled)
218 |
219 | **Note:**
220 | Cost estimation is now enabled for this organization. This feature will:
221 | - Show estimated costs for all Terraform plans
222 | - Calculate cost impact of planned changes
223 | - Display cost breakdowns by resource type
224 | - Show cost trend analysis
225 |
226 | The cost estimation feature uses cloud provider pricing data to estimate the cost of resources in your Terraform configurations. This can help teams understand the financial impact of their infrastructure changes before applying them.
227 | ```
228 |
229 | ```
230 | **User**: Change the email address for "terraform-demo" to "[email protected]"
231 |
232 | **Claude**: I'll update the email address for the "terraform-demo" organization.
233 |
234 | [Claude uses update_organization tool]
235 |
236 | I've successfully updated the email address for the "terraform-demo" organization. Here's the confirmation:
237 |
238 | **Organization Updated:**
239 | - Name: terraform-demo
240 | - New Email: [email protected] (previously [email protected])
241 | - ID: org-Bzyc2JuegvVLAibn
242 |
243 | The organization's notification email has been changed to [email protected]. All system notifications and alerts will now be sent to this address.
244 | ```
245 |
246 | ```
247 | **User**: Delete the "test-org" organization
248 |
249 | **Claude**: I'll help you delete the "test-org" organization. This is a significant action that will permanently delete all resources.
250 |
251 | [Claude uses delete_organization tool]
252 |
253 | **Organization Deletion Successful**
254 |
255 | The "test-org" organization has been permanently deleted. All associated resources have been removed:
256 | - All workspaces and their configurations
257 | - All state files and state versions
258 | - All team memberships and user associations
259 | - All variables, policy sets, and modules
260 |
261 | The organization name "test-org" is now available for use again if you wish to recreate it in the future.
262 |
263 | **Note**: This operation is irreversible. All data associated with the organization has been permanently deleted.
264 | ```
```
--------------------------------------------------------------------------------
/docs/tools/run.md:
--------------------------------------------------------------------------------
```markdown
1 | # Run Tools
2 |
3 | This module provides tools for managing runs in Terraform Cloud.
4 |
5 | ## Overview
6 |
7 | Runs in Terraform Cloud represent the process of executing Terraform operations (plan, apply) on a workspace. These tools allow you to create, list, and manage runs, including applying, discarding, and canceling them as needed.
8 |
9 | ## API Reference
10 |
11 | These tools interact with the Terraform Cloud Runs API:
12 | - [Runs API Documentation](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/run)
13 | - [Run Workflow](https://developer.hashicorp.com/terraform/cloud-docs/run/states)
14 |
15 | ## Tools Reference
16 |
17 | ### create_run
18 |
19 | **Function:** `create_run(workspace_id: str, params: Optional[RunParams] = None) -> Dict[str, Any]`
20 |
21 | **Description:** Creates and queues a new Terraform run in a workspace.
22 |
23 | **Parameters:**
24 | - `workspace_id` (str): The workspace ID to execute the run in (format: "ws-xxxxxxxx")
25 | - `params` (RunParams, optional): Run configuration options:
26 | - `message`: Description of the run's purpose
27 | - `is_destroy`: Whether to destroy all resources (default: False)
28 | - `auto_apply`: Whether to auto-apply after a successful plan
29 | - `refresh`: Whether to refresh state before planning (default: True)
30 | - `refresh_only`: Only refresh the state without planning changes
31 | - `plan_only`: Create a speculative plan without applying
32 | - `target_addrs`: List of resource addresses to target
33 | - `replace_addrs`: List of resource addresses to force replacement
34 | - `variables`: Run-specific variable overrides
35 |
36 | **Returns:** JSON response with run details including:
37 | - Run ID and creation timestamp
38 | - Status and status timestamps
39 | - Relationships to workspace, configuration version, and plan
40 |
41 | **Notes:**
42 | - Requires "queue run" permission on the workspace
43 | - Workspace must be unlocked to create a run
44 | - Only one run can be active in a workspace at a time
45 | - Run execution depends on the workspace's execution mode
46 |
47 | ### list_runs_in_workspace
48 |
49 | **Function:** `list_runs_in_workspace(workspace_id: str, page_number: int = 1, page_size: int = 20, filter_operation: Optional[str] = None, filter_status: Optional[str] = None, filter_source: Optional[str] = None, filter_status_group: Optional[str] = None, filter_timeframe: Optional[str] = None, filter_agent_pool_names: Optional[str] = None, search_user: Optional[str] = None, search_commit: Optional[str] = None, search_basic: Optional[str] = None) -> Dict[str, Any]`
50 |
51 | **Description:** Lists and filters runs in a specific workspace.
52 |
53 | **Parameters:**
54 | - `workspace_id` (str): The workspace ID (format: "ws-xxxxxxxx")
55 | - `page_number` (int, optional): Page number to fetch (default: 1)
56 | - `page_size` (int, optional): Number of results per page (default: 20)
57 | - `filter_operation`: Filter by operation type (e.g., "plan,apply")
58 | - `filter_status`: Filter by status (e.g., "pending,planning,applying")
59 | - `filter_source`: Filter by source (e.g., "tfe-ui,tfe-api")
60 | - `filter_status_group`: Filter by status group (e.g., "running,pending")
61 | - And many other filtering options...
62 |
63 | **Returns:** JSON response with paginated list of runs and metadata.
64 |
65 | **Notes:**
66 | - Requires "read runs" permission on the workspace
67 | - Use multiple comma-separated values for filter parameters
68 | - Results are sorted with most recent runs first
69 |
70 | ### list_runs_in_organization
71 |
72 | **Function:** `list_runs_in_organization(organization: str, page_number: int = 1, page_size: int = 20, filter_operation: Optional[str] = None, filter_status: Optional[str] = None, filter_source: Optional[str] = None, filter_status_group: Optional[str] = None, filter_timeframe: Optional[str] = None, filter_agent_pool_names: Optional[str] = None, filter_workspace_names: Optional[str] = None, search_user: Optional[str] = None, search_commit: Optional[str] = None, search_basic: Optional[str] = None) -> Dict[str, Any]`
73 |
74 | **Description:** Lists runs across all workspaces in an organization.
75 |
76 | **Parameters:**
77 | - `organization` (str): The organization name
78 | - Same filtering parameters as list_runs_in_workspace plus:
79 | - `filter_workspace_names` (str, optional): Filter by workspace names
80 |
81 | **Returns:** JSON response with paginated list of runs across the organization.
82 |
83 | **Notes:**
84 | - Requires appropriate permissions on workspaces
85 | - Useful for organization-wide auditing and monitoring
86 | - Returns only runs from workspaces the user has access to
87 |
88 | ### get_run_details
89 |
90 | **Function:** `get_run_details(run_id: str) -> Dict[str, Any]`
91 |
92 | **Description:** Gets detailed information about a specific run.
93 |
94 | **Parameters:**
95 | - `run_id` (str): The ID of the run (format: "run-xxxxxxxx")
96 |
97 | **Returns:** JSON response with comprehensive run details including:
98 | - Run status and phase information
99 | - Timestamps for each state transition
100 | - Configuration information
101 | - Relationships to plans, applies, and cost estimates
102 |
103 | **Notes:**
104 | - Requires "read runs" permission on the associated workspace
105 | - Provides access to related resources via relationships
106 |
107 | ### apply_run
108 |
109 | **Function:** `apply_run(run_id: str, comment: str = "") -> Dict[str, Any]`
110 |
111 | **Description:** Confirms and applies a run that is paused waiting for confirmation.
112 |
113 | **Parameters:**
114 | - `run_id` (str): The ID of the run to apply
115 | - `comment` (str, optional): Comment explaining the approval reason
116 |
117 | **Returns:** JSON response with updated run details.
118 |
119 | **Notes:**
120 | - Requires "apply" permission on the workspace
121 | - Run must be in "planned" status with changes to apply
122 | - Comment is recorded in the audit log
123 |
124 | ### discard_run
125 |
126 | **Function:** `discard_run(run_id: str, comment: str = "") -> Dict[str, Any]`
127 |
128 | **Description:** Discards a run that is paused waiting for confirmation.
129 |
130 | **Parameters:**
131 | - `run_id` (str): The ID of the run to discard
132 | - `comment` (str, optional): Comment explaining the discard reason
133 |
134 | **Returns:** JSON response with updated run details showing discarded state.
135 |
136 | **Notes:**
137 | - Requires "apply" permission on the workspace
138 | - Run must be in "planned" status to be discarded
139 | - Discarded runs cannot be applied later
140 |
141 | ### cancel_run
142 |
143 | **Function:** `cancel_run(run_id: str, comment: str = "") -> Dict[str, Any]`
144 |
145 | **Description:** Gracefully cancels a run that is currently planning or applying.
146 |
147 | **Parameters:**
148 | - `run_id` (str): The ID of the run to cancel
149 | - `comment` (str, optional): Comment explaining the cancellation reason
150 |
151 | **Returns:** JSON response with updated run details showing canceled state.
152 |
153 | **Notes:**
154 | - Requires "cancel" permission on the workspace
155 | - Run must be in an active state (planning, applying)
156 | - Attempts to gracefully terminate the process
157 |
158 | ### force_cancel_run
159 |
160 | **Function:** `force_cancel_run(run_id: str, comment: str = "") -> Dict[str, Any]`
161 |
162 | **Description:** Force cancels a run immediately.
163 |
164 | **Parameters:**
165 | - `run_id` (str): The ID of the run to force cancel
166 | - `comment` (str, optional): Comment explaining the force cancellation reason
167 |
168 | **Returns:** JSON response with updated run details showing force-canceled state.
169 |
170 | **Notes:**
171 | - Requires "cancel" permission on the workspace
172 | - Use only when normal cancellation doesn't work
173 | - May result in inconsistent state if used during apply
174 | - Immediately unlocks the workspace
175 |
176 | ### force_execute_run
177 |
178 | **Function:** `force_execute_run(run_id: str) -> Dict[str, Any]`
179 |
180 | **Description:** Cancels all prior runs to execute a specific run immediately.
181 |
182 | **Parameters:**
183 | - `run_id` (str): The ID of the run to execute
184 |
185 | **Returns:** JSON response confirming the run has been promoted.
186 |
187 | **Notes:**
188 | - Requires "cancel" permission on the workspace
189 | - Cancels all pending runs in the queue to prioritize this run
190 | - Useful for urgent changes or when runs are queued
191 |
192 | **Common Error Scenarios:**
193 |
194 | | Error | Cause | Solution |
195 | |-------|-------|----------|
196 | | 404 | Run not found | Verify the run ID |
197 | | 403 | Insufficient permissions | Ensure you have proper permissions |
198 | | 409 | Run cannot be applied/discarded/canceled | Verify run is in correct state |
199 | | 422 | Workspace locked by another run | Wait for the current run to finish or cancel it |
200 | | 409 | Workspace already has active run | Cancel the active run or wait for it to complete |
```
--------------------------------------------------------------------------------
/docs/API_REFERENCES.md:
--------------------------------------------------------------------------------
```markdown
1 | # Terraform Cloud API References
2 |
3 | This document contains links to all available Terraform Cloud API reference documentation.
4 |
5 | ## Implementation Status
6 |
7 | ✅ = Implemented with response filtering optimization
8 | ⏸️ = Not yet implemented
9 | 💰 = Requires paid Terraform Cloud tier
10 |
11 | ## API Documentation
12 |
13 | ### Core
14 | - [Overview](https://developer.hashicorp.com/terraform/cloud-docs/api-docs)
15 | - [Changelog](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/changelog)
16 | - [Stability Policy](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/stability-policy)
17 |
18 | ### APIs
19 | - [✅] [Account](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/account) - User profile and authentication info
20 | - [⏸️] [Agent Pools](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/agents) 💰 - Private agent management
21 | - [⏸️] [Agent Tokens](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/agent-tokens) 💰 - Agent authentication
22 | - [✅] [Applies](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/applies) - Infrastructure apply operations
23 | - [⏸️] [Audit Trails](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/audit-trails) 💰💰💰 - Organization audit logs
24 | - [⏸️] [Audit Trails Tokens](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/audit-trails-tokens) 💰💰💰 - Audit access tokens
25 | - [✅] [Assessment Results](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/assessment-results) 💰💰💰 - Health assessments
26 | - [⏸️] [Change Requests](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/change-requests) 💰💰💰 - Infrastructure change workflows
27 | - [⏸️] [Comments](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/comments) - Run and plan comments
28 | - [⏸️] [Configuration Versions](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/configuration-versions) - Terraform configuration uploads
29 | - [✅] [Cost Estimates](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/cost-estimates) - Infrastructure cost projections
30 | - [ ] [Explorer](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/explorer)
31 | - [ ] [Feature Sets](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/feature-sets) 💰
32 | - [ ] [GitHub App Installations](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/github-app-installations)
33 | - [ ] [Invoices](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/invoices)
34 | - [ ] [IP Ranges](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/ip-ranges)
35 | - [ ] [No-Code Provisioning](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/no-code-provisioning)
36 | - [ ] [Notification Configurations](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/notification-configurations)
37 | - [ ] [OAuth Clients](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/oauth-clients)
38 | - [ ] [OAuth Tokens](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/oauth-tokens)
39 | - [✅] [Organizations](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations) - Organization settings and management
40 | - [⏸️] [Organization Memberships](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organization-memberships) - User membership management
41 | - [⏸️] [Organization Tags](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organization-tags) - Organization-wide tagging
42 | - [⏸️] [Organization Tokens](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organization-tokens) - API token management
43 | - [⏸️] [Plan Exports](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/plan-exports) - Plan data export functionality
44 | - [✅] [Plans](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/plans) - Terraform execution plans
45 | - [ ] [Policies](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/policies) 💰💰
46 | - [ ] [Policy Checks](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/policy-checks) 💰💰
47 | - [ ] [Policy Evaluations](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/policy-evaluations) 💰💰
48 | - [ ] [Policy Sets](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/policy-sets) 💰💰
49 | - [ ] [Policy Set Parameters](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/policy-set-params) 💰💰
50 | - Private Registry
51 | - [ ] [Modules](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/private-registry/modules)
52 | - [ ] [Manage Module Versions](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/private-registry/manage-module-versions)
53 | - [ ] [Providers](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/private-registry/providers)
54 | - [ ] [Private Provider Versions and Platforms](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/private-registry/provider-versions-platforms)
55 | - [ ] [GPG Keys](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/private-registry/gpg-keys)
56 | - [ ] [Tests](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/private-registry/tests)
57 | - [✅] [Projects](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects) - Workspace organization and management
58 | - [⏸️] [Project Team Access](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/project-team-access) 💰 - Team permissions for projects
59 | - [⏸️] [Reserved Tag Keys](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/reserved-tag-keys) - System-reserved tag management
60 | - [✅] [Runs](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/run) - Terraform execution runs
61 | - Run Tasks
62 | - [ ] [Run Tasks](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/run-tasks/run-tasks) 💰💰
63 | - [ ] [Stages and Results](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/run-tasks/run-task-stages-and-results) 💰💰
64 | - [ ] [Custom Integration](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/run-tasks/run-tasks-integration) 💰💰
65 | - [ ] [Run Triggers](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/run-triggers)
66 | - [ ] [SSH Keys](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/ssh-keys)
67 | - [✅] [State Versions](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions) - Terraform state management
68 | - [✅] [State Version Outputs](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-version-outputs) - State output values
69 | - [⏸️] [Subscriptions](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/subscriptions) - Billing and subscription management
70 | - [⏸️] [Team Membership](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/team-members) 💰 - Team member management
71 | - [⏸️] [Team Tokens](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/team-tokens) 💰 - Team-level API tokens
72 | - [⏸️] [Teams](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/teams) 💰 - Team management
73 | - [⏸️] [User Tokens](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/user-tokens) - User API token management
74 | - [⏸️] [Users](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/users) - User account management
75 | - [✅] [Variables](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variables) - Terraform variable management
76 | - [✅] [Variable Sets](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets) - Reusable variable collections
77 | - [⏸️] [VCS Events](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/vcs-events) - Version control system events
78 | - [✅] [Workspaces](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces) 💰 - Terraform workspace management
79 | - [✅] [Workspace-Specific Variables](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-variables) - Workspace variable management
80 | - [⏸️] [Workspace Team Access](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/team-access) 💰 - Team permissions for workspaces
81 | - [⏸️] [Workspace Resources](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-resources) - Resource tracking and management
```
--------------------------------------------------------------------------------
/terraform_cloud_mcp/tools/state_versions.py:
--------------------------------------------------------------------------------
```python
1 | """Terraform Cloud state version management tools.
2 |
3 | This module provides tools for working with state versions in Terraform Cloud.
4 | It includes functions to retrieve, list, and create state versions.
5 |
6 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/state-versions
7 | """
8 |
9 | from typing import Optional
10 |
11 | from ..api.client import api_request
12 | from ..models.base import APIResponse
13 | from ..models.state_versions import (
14 | CurrentStateVersionRequest,
15 | StateVersionCreateRequest,
16 | StateVersionListRequest,
17 | StateVersionParams,
18 | StateVersionRequest,
19 | StateVersionStatus,
20 | )
21 | from ..utils.decorators import handle_api_errors
22 | from ..utils.payload import create_api_payload, add_relationship
23 | from ..utils.request import query_params
24 |
25 |
26 | @handle_api_errors
27 | async def list_state_versions(
28 | organization: str,
29 | workspace_name: str,
30 | page_number: int = 1,
31 | page_size: int = 20,
32 | filter_status: Optional[str] = None,
33 | ) -> APIResponse:
34 | """List state versions in a workspace.
35 |
36 | Retrieves a paginated list of all state versions in a Terraform Cloud workspace.
37 | Results can be filtered using status to find specific state versions.
38 |
39 | API endpoint: GET /state-versions
40 |
41 | Args:
42 | organization: The name of the organization that owns the workspace
43 | workspace_name: The name of the workspace to list state versions from
44 | page_number: The page number to return (default: 1)
45 | page_size: The number of items per page (default: 20, max: 100)
46 | filter_status: Filter state versions by status: 'pending', 'finalized', or 'discarded'
47 |
48 | Returns:
49 | Paginated list of state versions with their configuration settings and metadata
50 |
51 | See:
52 | docs/tools/state_versions.md for reference documentation
53 | """
54 | # Convert filter_status string to enum if provided
55 | status_enum = None
56 | if filter_status:
57 | try:
58 | status_enum = StateVersionStatus(filter_status)
59 | except ValueError:
60 | valid_values = ", ".join([s.value for s in StateVersionStatus])
61 | raise ValueError(
62 | f"Invalid filter_status value: {filter_status}. Valid values: {valid_values}"
63 | )
64 |
65 | # Validate parameters
66 | params = StateVersionListRequest(
67 | filter_workspace_name=workspace_name,
68 | filter_organization_name=organization,
69 | page_number=page_number,
70 | page_size=page_size,
71 | filter_status=status_enum,
72 | )
73 |
74 | # Build query parameters using utility function
75 | query = query_params(params)
76 |
77 | # Make API request
78 | return await api_request("state-versions", params=query)
79 |
80 |
81 | @handle_api_errors
82 | async def get_current_state_version(workspace_id: str) -> APIResponse:
83 | """Get the current state version for a workspace.
84 |
85 | Retrieves the current state version for a workspace, which is the input
86 | state when running terraform operations.
87 |
88 | API endpoint: GET /workspaces/:workspace_id/current-state-version
89 |
90 | Args:
91 | workspace_id: The ID of the workspace (format: "ws-xxxxxxxx")
92 |
93 | Returns:
94 | The current state version including details and download URLs
95 |
96 | See:
97 | docs/tools/state_versions.md for reference documentation
98 | """
99 | # Validate parameters
100 | params = CurrentStateVersionRequest(workspace_id=workspace_id)
101 |
102 | # Make API request
103 | return await api_request(f"workspaces/{params.workspace_id}/current-state-version")
104 |
105 |
106 | @handle_api_errors
107 | async def get_state_version(state_version_id: str) -> APIResponse:
108 | """Get details for a specific state version.
109 |
110 | Retrieves comprehensive information about a state version including its status,
111 | download URLs, and resource information.
112 |
113 | API endpoint: GET /state-versions/:state_version_id
114 |
115 | Args:
116 | state_version_id: The ID of the state version to retrieve (format: "sv-xxxxxxxx")
117 |
118 | Returns:
119 | State version details including status, timestamps, and resource metadata
120 |
121 | See:
122 | docs/tools/state_versions.md for reference documentation
123 | """
124 | # Validate parameters
125 | params = StateVersionRequest(state_version_id=state_version_id)
126 |
127 | # Make API request
128 | return await api_request(f"state-versions/{params.state_version_id}")
129 |
130 |
131 | @handle_api_errors
132 | async def create_state_version(
133 | workspace_id: str,
134 | serial: int,
135 | md5: str,
136 | params: Optional[StateVersionParams] = None,
137 | ) -> APIResponse:
138 | """Create a state version in a workspace.
139 |
140 | Creates a new state version and sets it as the current state version for the
141 | given workspace. The workspace must be locked by the user creating a state version.
142 | This is most useful for migrating existing state from Terraform Community edition
143 | into a new HCP Terraform workspace.
144 |
145 | API endpoint: POST /workspaces/:workspace_id/state-versions
146 |
147 | Args:
148 | workspace_id: The ID of the workspace (format: "ws-xxxxxxxx")
149 | serial: The serial number of this state instance
150 | md5: An MD5 hash of the raw state version
151 | params: Additional state version parameters (optional):
152 | - state: Base64 encoded raw state file
153 | - lineage: Lineage of the state version
154 | - json_state: Base64 encoded JSON state
155 | - json_state_outputs: Base64 encoded JSON state outputs
156 | - run_id: The ID of the run to associate with the state version
157 |
158 | Returns:
159 | The created state version data including download URLs and status information
160 |
161 | See:
162 | docs/tools/state_versions.md for reference documentation
163 | """
164 | # Extract parameters from params object
165 | param_dict = params.model_dump(exclude_none=True, by_alias=False) if params else {}
166 |
167 | # Add required parameters
168 | param_dict["serial"] = serial
169 | param_dict["md5"] = md5
170 |
171 | # Create request using Pydantic model
172 | request_params = StateVersionCreateRequest(workspace_id=workspace_id, **param_dict)
173 |
174 | # Create API payload using utility function
175 | payload = create_api_payload(
176 | resource_type="state-versions",
177 | model=request_params,
178 | exclude_fields={"workspace_id"},
179 | )
180 |
181 | # Add relationship if run_id is provided
182 | if param_dict.get("run_id"):
183 | payload = add_relationship(
184 | payload=payload,
185 | relation_name="run",
186 | resource_type="runs",
187 | resource_id=param_dict["run_id"],
188 | )
189 |
190 | # Make API request
191 | return await api_request(
192 | f"workspaces/{request_params.workspace_id}/state-versions",
193 | method="POST",
194 | data=payload,
195 | )
196 |
197 |
198 | @handle_api_errors
199 | async def download_state_file(
200 | state_version_id: str, json_format: bool = False
201 | ) -> APIResponse:
202 | """Download the state file content.
203 |
204 | Retrieves the raw state file or JSON formatted state file for a specific state version.
205 |
206 | API endpoint: Uses the hosted URLs from GET /state-versions/:state_version_id
207 |
208 | Args:
209 | state_version_id: The ID of the state version (format: "sv-xxxxxxxx")
210 | json_format: Whether to download the JSON formatted state (default: False)
211 |
212 | Returns:
213 | The raw state file content or JSON formatted state content
214 |
215 | See:
216 | docs/tools/state_versions.md for reference documentation
217 | """
218 | # Validate parameters
219 | params = StateVersionRequest(state_version_id=state_version_id)
220 |
221 | # First get state version details to get the download URL
222 | state_version = await api_request(f"state-versions/{params.state_version_id}")
223 |
224 | # Determine which URL to use based on format request
225 | url_attr = (
226 | "hosted-json-state-download-url" if json_format else "hosted-state-download-url"
227 | )
228 | download_url = state_version.get("data", {}).get("attributes", {}).get(url_attr)
229 |
230 | # Check if URL is available
231 | if not download_url:
232 | if json_format:
233 | return {
234 | "error": "JSON state download URL not available. This may be because the state was not created with Terraform 1.3+"
235 | }
236 | else:
237 | return {"error": "State download URL not available for this state version"}
238 |
239 | # Use the enhanced api_request to fetch state from the external URL
240 | return await api_request(download_url, external_url=True, accept_text=True)
241 |
```