#
tokens: 49760/50000 24/92 files (page 2/4)
lines: on (toggle) GitHub
raw markdown copy reset
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 | 
```
Page 2/4FirstPrevNextLast