#
tokens: 45941/50000 14/92 files (page 3/4)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 3 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/organization.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Organization Models
  2 | 
  3 | This document describes the data models used for organization operations in Terraform Cloud.
  4 | 
  5 | ## Overview
  6 | 
  7 | Organization models provide structure and validation for interacting with the Terraform Cloud Organizations API. These models define organization settings, authentication policies, and default configurations for workspaces.
  8 | 
  9 | ## Models Reference
 10 | 
 11 | ### CollaboratorAuthPolicy
 12 | 
 13 | **Type:** Enum (string)
 14 | 
 15 | **Description:** Authentication policy options for organization collaborators.
 16 | 
 17 | **Values:**
 18 | - `password`: Password-only authentication is allowed
 19 | - `two_factor_mandatory`: Two-factor authentication is required for all users
 20 | 
 21 | **JSON representation:**
 22 | ```json
 23 | {
 24 |   "collaborator-auth-policy": "two_factor_mandatory"
 25 | }
 26 | ```
 27 | 
 28 | **Usage Context:**
 29 | Used to enforce security policies across an organization. Setting this to `two_factor_mandatory` requires all users to have 2FA enabled before they can access organization resources.
 30 | 
 31 | ### ExecutionMode
 32 | 
 33 | **Type:** Enum (string)
 34 | 
 35 | **Description:** Execution mode options for workspaces and organizations.
 36 | 
 37 | **Values:**
 38 | - `remote`: Terraform runs on Terraform Cloud's infrastructure
 39 | - `local`: Terraform runs on your local machine
 40 | - `agent`: Terraform runs on your own infrastructure using an agent
 41 | 
 42 | **JSON representation:**
 43 | ```json
 44 | {
 45 |   "default-execution-mode": "remote"
 46 | }
 47 | ```
 48 | 
 49 | **Usage Context:**
 50 | Used to define how Terraform operations are executed for workspaces in an organization.
 51 | 
 52 | ### OrganizationParams
 53 | 
 54 | **Type:** Object
 55 | 
 56 | **Description:** Parameters for organization operations. Used to configure organization settings when creating or updating organizations.
 57 | 
 58 | **Fields:**
 59 | - `name` (string, optional): Name of the organization (min length: 3, must match pattern: ^[a-z0-9][-a-z0-9_]*[a-z0-9]$)
 60 | - `email` (string, optional): Admin email address (must be valid email format)
 61 | - `collaborator_auth_policy` (CollaboratorAuthPolicy, optional): Authentication policy (password or two_factor_mandatory)
 62 | - `session_timeout` (integer, optional): Session timeout after inactivity in minutes (default: 20160)
 63 | - `session_remember` (integer, optional): Session total expiration time in minutes (default: 20160)
 64 | - `cost_estimation_enabled` (boolean, optional): Whether to enable cost estimation (default: false)
 65 | - `default_execution_mode` (ExecutionMode, optional): Default execution mode for workspaces (remote, local, agent)
 66 | - `aggregated_commit_status_enabled` (boolean, optional): Whether to aggregate VCS status updates (default: true)
 67 | - `speculative_plan_management_enabled` (boolean, optional): Whether to auto-cancel unused speculative plans (default: true)
 68 | - `assessments_enforced` (boolean, optional): Whether to enforce health assessments for all workspaces (default: false)
 69 | - `allow_force_delete_workspaces` (boolean, optional): Allow deleting workspaces with resources (default: false)
 70 | - `default_agent_pool_id` (string, optional): Default agent pool ID (required when default_execution_mode=agent)
 71 | - `owners_team_saml_role_id` (string, optional): The SAML role for owners team
 72 | - `send_passing_statuses_for_untriggered_speculative_plans` (boolean, optional): Whether to send VCS status for untriggered plans (default: false)
 73 | 
 74 | **JSON representation:**
 75 | ```json
 76 | {
 77 |   "data": {
 78 |     "type": "organizations",
 79 |     "attributes": {
 80 |       "name": "my-organization",
 81 |       "email": "[email protected]",
 82 |       "session-timeout": 60,
 83 |       "session-remember": 1440,
 84 |       "collaborator-auth-policy": "two_factor_mandatory",
 85 |       "cost-estimation-enabled": true,
 86 |       "default-execution-mode": "remote",
 87 |       "assessments-enforced": true
 88 |     }
 89 |   }
 90 | }
 91 | ```
 92 | 
 93 | **Notes:**
 94 | - Field names in JSON use kebab-case format (e.g., "default-execution-mode")
 95 | - Field names in the model use snake_case format (e.g., default_execution_mode)
 96 | - All fields are optional when updating (PATCH) but name and email are required when creating (POST)
 97 | 
 98 | **Validation Rules:**
 99 | - Organization names must be 3 or more characters
100 | - Organization names must start and end with a lowercase letter or number
101 | - Organization names may contain lowercase letters, numbers, hyphens, and underscores
102 | - Email addresses must be valid format
103 | - Session timeouts and remembers must be between 1 and 43200 minutes (30 days)
104 | 
105 | ### OrganizationDetailsRequest
106 | 
107 | **Type:** Request Validation Model
108 | 
109 | **Description:** Used to validate parameters for retrieving organization details.
110 | 
111 | **Fields:**
112 | - `organization` (string, required): The name of the organization to retrieve details for
113 | 
114 | **Used by:**
115 | - `get_organization_details` tool function to validate the organization name parameter
116 | 
117 | ### OrganizationEntitlementsRequest
118 | 
119 | **Type:** Request Validation Model
120 | 
121 | **Description:** Used to validate parameters for retrieving organization entitlements.
122 | 
123 | **Fields:**
124 | - `organization` (string, required): The name of the organization to retrieve entitlements for
125 | 
126 | **Used by:**
127 | - `get_organization_entitlements` tool function to validate the organization name parameter
128 | 
129 | ### OrganizationDeleteRequest
130 | 
131 | **Type:** Request Validation Model
132 | 
133 | **Description:** Used to validate parameters for deleting an organization.
134 | 
135 | **Fields:**
136 | - `organization` (string, required): The name of the organization to delete
137 | 
138 | **Used by:**
139 | - `delete_organization` tool function to validate the organization name parameter
140 | 
141 | ### OrganizationListRequest
142 | 
143 | **Type:** Request Validation Model
144 | 
145 | **Description:** Used to validate parameters for listing organizations.
146 | 
147 | **Fields:**
148 | - `page_number` (int, optional): Page number to return (default: 1)
149 | - `page_size` (int, optional): Number of items per page (default: 20)
150 | - `q` (str, optional): Search query to filter by name and email
151 | - `query_email` (str, optional): Search query to filter by email only
152 | - `query_name` (str, optional): Search query to filter by name only
153 | 
154 | **Used by:**
155 | - `list_organizations` tool function to validate pagination and search parameters
156 | 
157 | ### OrganizationCreateRequest
158 | 
159 | **Type:** Request Validation Model
160 | 
161 | **Description:** Used to validate parameters for creating an organization.
162 | 
163 | **Fields:**
164 | - `name` (string, required): The name for the organization
165 | - `email` (string, required): Admin email address
166 | - `params` (OrganizationParams, optional): Additional configuration options
167 | 
168 | **Used by:**
169 | - `create_organization` tool function to validate organization creation parameters
170 | 
171 | ### OrganizationUpdateRequest
172 | 
173 | **Type:** Request Validation Model
174 | 
175 | **Description:** Used to validate parameters for updating an organization.
176 | 
177 | **Fields:**
178 | - `organization` (string, required): The name of the organization to update
179 | - `params` (OrganizationParams, optional): Settings to update
180 | 
181 | **Used by:**
182 | - `update_organization` tool function to validate organization update parameters
183 | 
184 | ## API Response Structure
185 | 
186 | ### Organization Details Response
187 | 
188 | ```json
189 | {
190 |   "data": {
191 |     "id": "org-ABcd1234",
192 |     "type": "organizations",
193 |     "attributes": {
194 |       "name": "my-organization",
195 |       "external-id": "org-12345",
196 |       "created-at": "2023-01-15T12:34:56Z",
197 |       "email": "[email protected]",
198 |       "session-timeout": 60,
199 |       "session-remember": 1440,
200 |       "collaborator-auth-policy": "two_factor_mandatory",
201 |       "cost-estimation-enabled": true,
202 |       "default-execution-mode": "remote",
203 |       "permissions": {
204 |         "can-destroy": true,
205 |         "can-update": true
206 |       }
207 |     },
208 |     "relationships": {
209 |       "subscription": {
210 |         "data": {
211 |           "id": "sub-XYZ789",
212 |           "type": "subscriptions"
213 |         }
214 |       }
215 |     },
216 |     "links": {
217 |       "self": "/api/v2/organizations/my-organization"
218 |     }
219 |   }
220 | }
221 | ```
222 | 
223 | ### Organization Entitlements Response
224 | 
225 | ```json
226 | {
227 |   "data": {
228 |     "id": "org-ABcd1234",
229 |     "type": "organization-entitlements",
230 |     "attributes": {
231 |       "cost-estimation": true,
232 |       "operations": true,
233 |       "private-modules": true,
234 |       "sentinel": true,
235 |       "teams": true,
236 |       "vcs-integrations": true,
237 |       "usage-reporting": true,
238 |       "self-serve-billing": true,
239 |       "state-storage": {
240 |         "unlimited": true
241 |       },
242 |       "teams": {
243 |         "limit": 5,
244 |         "used": 3
245 |       },
246 |       "private-module-registry": {
247 |         "limit": 100,
248 |         "used": 25
249 |       }
250 |     }
251 |   }
252 | }
253 | ```
254 | 
255 | ## Related Resources
256 | 
257 | - [Organization Tools](../tools/organization.md)
258 | - [Workspace Models](workspace.md)
259 | - [Terraform Cloud API - Organizations](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations)
```

--------------------------------------------------------------------------------
/terraform_cloud_mcp/tools/organizations.py:
--------------------------------------------------------------------------------

```python
  1 | """Organization management tools for Terraform Cloud MCP
  2 | 
  3 | This module implements the /organizations endpoints of the Terraform Cloud API.
  4 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations
  5 | """
  6 | 
  7 | from typing import Optional
  8 | 
  9 | from ..api.client import api_request
 10 | from ..utils.decorators import handle_api_errors
 11 | from ..utils.payload import create_api_payload
 12 | from ..utils.request import query_params
 13 | from ..models.base import APIResponse
 14 | from ..models.organizations import (
 15 |     OrganizationCreateRequest,
 16 |     OrganizationUpdateRequest,
 17 |     OrganizationListRequest,
 18 |     OrganizationParams,
 19 |     OrganizationDetailsRequest,
 20 |     OrganizationEntitlementsRequest,
 21 |     OrganizationDeleteRequest,
 22 | )
 23 | 
 24 | 
 25 | @handle_api_errors
 26 | async def get_organization_details(organization: str) -> APIResponse:
 27 |     """Get details for a specific organization
 28 | 
 29 |     Retrieves comprehensive information about an organization including settings,
 30 |     email contact info, and configuration defaults.
 31 | 
 32 |     API endpoint: GET /organizations/{organization}
 33 | 
 34 |     Args:
 35 |         organization: The organization name to retrieve details for (required)
 36 | 
 37 |     Returns:
 38 |         Organization details including name, email, settings and configuration
 39 | 
 40 |     See:
 41 |         docs/tools/organization.md for reference documentation
 42 |     """
 43 |     request = OrganizationDetailsRequest(organization=organization)
 44 |     return await api_request(f"organizations/{request.organization}")
 45 | 
 46 | 
 47 | @handle_api_errors
 48 | async def get_organization_entitlements(organization: str) -> APIResponse:
 49 |     """Show entitlement set for organization features
 50 | 
 51 |     Retrieves information about available features and capabilities based on
 52 |     the organization's subscription tier.
 53 | 
 54 |     API endpoint: GET /organizations/{organization}/entitlement-set
 55 | 
 56 |     Args:
 57 |         organization: The organization name to retrieve entitlements for (required)
 58 | 
 59 |     Returns:
 60 |         Entitlement set details including feature limits and subscription information
 61 | 
 62 |     See:
 63 |         docs/tools/organization.md for reference documentation
 64 |     """
 65 |     request = OrganizationEntitlementsRequest(organization=organization)
 66 |     return await api_request(f"organizations/{request.organization}/entitlement-set")
 67 | 
 68 | 
 69 | @handle_api_errors
 70 | async def list_organizations(
 71 |     page_number: int = 1,
 72 |     page_size: int = 20,
 73 |     q: Optional[str] = None,
 74 |     query_email: Optional[str] = None,
 75 |     query_name: Optional[str] = None,
 76 | ) -> APIResponse:
 77 |     """List organizations with filtering options
 78 | 
 79 |     Retrieves a paginated list of organizations the current user has access to,
 80 |     with options to search by name or email address.
 81 | 
 82 |     API endpoint: GET /organizations
 83 | 
 84 |     Args:
 85 |         page_number: Page number to fetch (default: 1)
 86 |         page_size: Number of results per page (default: 20)
 87 |         q: Search query to filter by name and email
 88 |         query_email: Search query to filter by email only
 89 |         query_name: Search query to filter by name only
 90 | 
 91 |     Returns:
 92 |         List of organizations with metadata and pagination information
 93 | 
 94 |     See:
 95 |         docs/tools/organization.md for reference documentation
 96 |     """
 97 |     request = OrganizationListRequest(
 98 |         page_number=page_number,
 99 |         page_size=page_size,
100 |         q=q,
101 |         query_email=query_email,
102 |         query_name=query_name,
103 |     )
104 | 
105 |     # Get all query parameters - now automatically handles query_email and query_name
106 |     params = query_params(request)
107 | 
108 |     return await api_request("organizations", params=params)
109 | 
110 | 
111 | @handle_api_errors
112 | async def create_organization(
113 |     name: str, email: str, params: Optional[OrganizationParams] = None
114 | ) -> APIResponse:
115 |     """Create a new organization in Terraform Cloud
116 | 
117 |     Creates a new organization with the given name and email, allowing workspaces
118 |     and teams to be created within it. This is the first step in setting up a new
119 |     environment in Terraform Cloud.
120 | 
121 |     API endpoint: POST /organizations
122 | 
123 |     Args:
124 |         name: The name of the organization (required)
125 |         email: Admin email address (required)
126 |         params: Additional organization settings:
127 |             - collaborator_auth_policy: Authentication policy (password or two_factor_mandatory)
128 |             - session_timeout: Session timeout after inactivity in minutes
129 |             - session_remember: Session total expiration time in minutes
130 |             - cost_estimation_enabled: Whether to enable cost estimation for workspaces
131 |             - default_execution_mode: Default workspace execution mode (remote, local, agent)
132 |             - aggregated_commit_status_enabled: Whether to aggregate VCS status updates
133 |             - speculative_plan_management_enabled: Whether to auto-cancel unused speculative plans
134 |             - assessments_enforced: Whether to enforce health assessments for all workspaces
135 |             - allow_force_delete_workspaces: Whether to allow deleting workspaces with resources
136 |             - default_agent_pool_id: Default agent pool ID (required when using agent mode)
137 | 
138 |     Returns:
139 |         The created organization details including ID and created timestamp
140 | 
141 |     See:
142 |         docs/tools/organization.md for reference documentation
143 |     """
144 |     # Extract parameters from the params object if provided
145 |     param_dict = params.model_dump(exclude_none=True) if params else {}
146 | 
147 |     # Create request using Pydantic model with defaults
148 |     request = OrganizationCreateRequest(name=name, email=email, **param_dict)
149 | 
150 |     # Create API payload using utility function
151 |     payload = create_api_payload(resource_type="organizations", model=request)
152 | 
153 |     # Make the API request
154 |     return await api_request("organizations", method="POST", data=payload)
155 | 
156 | 
157 | @handle_api_errors
158 | async def update_organization(
159 |     organization: str, params: Optional[OrganizationParams] = None
160 | ) -> APIResponse:
161 |     """Update an existing organization in Terraform Cloud
162 | 
163 |     Modifies organization settings such as email contact, authentication policy,
164 |     or other configuration options. Only specified attributes will be updated.
165 | 
166 |     API endpoint: PATCH /organizations/{organization}
167 | 
168 |     Args:
169 |         organization: The name of the organization to update (required)
170 |         params: Organization parameters to update:
171 |             - email: Admin email address for the organization
172 |             - collaborator_auth_policy: Authentication policy (password or two_factor_mandatory)
173 |             - session_timeout: Session timeout after inactivity in minutes
174 |             - session_remember: Session total expiration time in minutes
175 |             - cost_estimation_enabled: Whether to enable cost estimation for workspaces
176 |             - default_execution_mode: Default workspace execution mode (remote, local, agent)
177 |             - aggregated_commit_status_enabled: Whether to aggregate VCS status updates
178 |             - speculative_plan_management_enabled: Whether to auto-cancel unused speculative plans
179 |             - assessments_enforced: Whether to enforce health assessments for all workspaces
180 |             - allow_force_delete_workspaces: Whether to allow deleting workspaces with resources
181 | 
182 |     Returns:
183 |         The updated organization with all current settings
184 | 
185 |     See:
186 |         docs/tools/organization.md for reference documentation
187 |     """
188 |     # Extract parameters from the params object if provided
189 |     param_dict = params.model_dump(exclude_none=True) if params else {}
190 | 
191 |     # Create request using Pydantic model
192 |     request = OrganizationUpdateRequest(organization=organization, **param_dict)
193 | 
194 |     # Create API payload using utility function
195 |     payload = create_api_payload(
196 |         resource_type="organizations", model=request, exclude_fields={"organization"}
197 |     )
198 | 
199 |     # Make the API request
200 |     return await api_request(
201 |         f"organizations/{organization}", method="PATCH", data=payload
202 |     )
203 | 
204 | 
205 | @handle_api_errors
206 | async def delete_organization(organization: str) -> APIResponse:
207 |     """Delete an organization from Terraform Cloud
208 | 
209 |     Permanently removes an organization including all its workspaces, teams, and resources.
210 |     This action cannot be undone. Organization names are globally unique and cannot be
211 |     recreated with the same name later.
212 | 
213 |     API endpoint: DELETE /organizations/{organization}
214 | 
215 |     Args:
216 |         organization: The name of the organization to delete (required)
217 | 
218 |     Returns:
219 |         Success confirmation (HTTP 204 No Content) or error details
220 | 
221 |     See:
222 |         docs/tools/organization.md for reference documentation
223 |     """
224 |     # Create request using Pydantic model
225 |     request = OrganizationDeleteRequest(organization=organization)
226 | 
227 |     # Make API request
228 |     return await api_request(f"organizations/{request.organization}", method="DELETE")
229 | 
```

--------------------------------------------------------------------------------
/terraform_cloud_mcp/utils/filters.py:
--------------------------------------------------------------------------------

```python
  1 | """Response filtering utilities for Terraform Cloud MCP
  2 | 
  3 | This module provides smart filtering of API responses to reduce token usage
  4 | while preserving essential data for MCP operations.
  5 | """
  6 | 
  7 | from typing import Dict, Any, Callable, Union
  8 | 
  9 | from ..models.filters import FilterConfig, OperationType, ResourceType, FilterRequest
 10 | from ..configs.filter_configs import (
 11 |     FILTER_CONFIGS,
 12 |     RESOURCE_TYPE_MAP,
 13 |     PATH_PATTERNS,
 14 |     DATA_TYPE_MAP,
 15 | )
 16 | 
 17 | 
 18 | def filter_response(
 19 |     data: Dict[str, Any],
 20 |     resource_type: Union[str, ResourceType],
 21 |     operation_type: Union[str, OperationType] = OperationType.READ,
 22 | ) -> Dict[str, Any]:
 23 |     """Filter API response to remove unnecessary fields."""
 24 |     if not isinstance(data, dict) or "data" not in data:
 25 |         return data
 26 | 
 27 |     # Shallow copy response for performance
 28 |     filtered_data = data.copy()
 29 |     if isinstance(filtered_data["data"], list):
 30 |         filtered_data["data"] = [
 31 |             item.copy() if isinstance(item, dict) else item
 32 |             for item in filtered_data["data"]
 33 |         ]
 34 |     elif isinstance(filtered_data["data"], dict):
 35 |         filtered_data["data"] = filtered_data["data"].copy()
 36 |     for key in ("meta", "links"):
 37 |         if key in filtered_data:
 38 |             filtered_data[key] = filtered_data[key].copy()
 39 | 
 40 |     # Normalize types to enums
 41 |     if isinstance(resource_type, str):
 42 |         normalized_type = RESOURCE_TYPE_MAP.get(resource_type, ResourceType.GENERIC)
 43 |     elif isinstance(resource_type, ResourceType):
 44 |         normalized_type = resource_type
 45 |     else:
 46 |         raise ValueError(f"Invalid resource_type: {resource_type}")
 47 | 
 48 |     if isinstance(operation_type, str):
 49 |         try:
 50 |             operation_enum = OperationType(operation_type)
 51 |         except ValueError:
 52 |             raise ValueError(f"Invalid operation_type: {operation_type}")
 53 |     elif isinstance(operation_type, OperationType):
 54 |         operation_enum = operation_type
 55 |     else:
 56 |         raise ValueError(f"Invalid operation_type: {operation_type}")
 57 | 
 58 |     # Handle single item or list of items
 59 |     if isinstance(filtered_data["data"], list):
 60 |         for item in filtered_data["data"]:
 61 |             _filter_item_attributes(item, normalized_type, operation_enum)
 62 |     else:
 63 |         _filter_item_attributes(filtered_data["data"], normalized_type, operation_enum)
 64 | 
 65 |     # Filter top-level metadata for list operations
 66 |     if operation_enum == OperationType.LIST:
 67 |         _filter_list_metadata(filtered_data)
 68 | 
 69 |     return filtered_data
 70 | 
 71 | 
 72 | def filter_with_request(data: Dict[str, Any], request: FilterRequest) -> Dict[str, Any]:
 73 |     """Filter API response using a FilterRequest object."""
 74 |     # Apply base filtering
 75 |     filtered_data = filter_response(data, request.resource_type, request.operation_type)
 76 | 
 77 |     # Apply custom field removals if specified
 78 |     if request.custom_fields:
 79 |         if isinstance(filtered_data["data"], list):
 80 |             for item in filtered_data["data"]:
 81 |                 _remove_custom_fields(item, request.custom_fields)
 82 |         else:
 83 |             _remove_custom_fields(filtered_data["data"], request.custom_fields)
 84 | 
 85 |     # Restore preserved fields if specified
 86 |     if request.preserve_fields:
 87 |         # This would require access to original data - placeholder for future implementation
 88 |         pass
 89 | 
 90 |     return filtered_data
 91 | 
 92 | 
 93 | def _filter_item_attributes(
 94 |     item: Dict[str, Any], resource_type: ResourceType, operation_type: OperationType
 95 | ) -> None:
 96 |     """Filter individual item attributes in-place."""
 97 |     if "attributes" not in item:
 98 |         return
 99 | 
100 |     # Shallow copy attributes to avoid modifying original
101 |     if not isinstance(item["attributes"], dict):
102 |         return
103 |     item["attributes"] = item["attributes"].copy()
104 |     attrs = item["attributes"]
105 | 
106 |     config = FILTER_CONFIGS.get(resource_type, FilterConfig())
107 | 
108 |     # Build set of fields to remove using Pydantic model
109 |     fields_to_remove = set(config.always_remove)
110 | 
111 |     if operation_type == OperationType.READ:
112 |         fields_to_remove.update(config.read_remove)
113 |     elif operation_type == OperationType.LIST:
114 |         fields_to_remove.update(config.list_remove)
115 | 
116 |     # Remove specified fields
117 |     for field in fields_to_remove:
118 |         attrs.pop(field, None)
119 | 
120 |     # Handle relationships
121 |     if "relationships" in item:
122 |         # Shallow copy relationships to avoid modifying original
123 |         item["relationships"] = item["relationships"].copy()
124 |         _filter_relationships(item["relationships"], resource_type, operation_type)
125 | 
126 |     # Remove item-level links
127 |     item.pop("links", None)
128 | 
129 | 
130 | def _filter_relationships(
131 |     relationships: Dict[str, Any],
132 |     resource_type: ResourceType,
133 |     operation_type: OperationType,
134 | ) -> None:
135 |     """Filter relationships in-place."""
136 |     config = FILTER_CONFIGS.get(resource_type, FilterConfig())
137 |     essential_rels = config.essential_relationships
138 | 
139 |     if operation_type == OperationType.READ and essential_rels:
140 |         # Keep only essential relationships
141 |         keys_to_remove = [k for k in relationships.keys() if k not in essential_rels]
142 |         for key in keys_to_remove:
143 |             relationships.pop(key, None)
144 | 
145 |     # Remove links from all remaining relationships
146 |     for key, rel_data in relationships.items():
147 |         if isinstance(rel_data, dict):
148 |             # Shallow copy individual relationship to avoid modifying original
149 |             relationships[key] = rel_data.copy()
150 |             relationships[key].pop("links", None)
151 | 
152 |     # Remove empty relationships
153 |     if not relationships:
154 |         return
155 | 
156 | 
157 | def _remove_custom_fields(item: Dict[str, Any], custom_fields: set[str]) -> None:
158 |     """Remove custom fields from an item."""
159 |     if "attributes" not in item or not isinstance(item["attributes"], dict):
160 |         return
161 | 
162 |     attrs = item["attributes"]
163 |     for field in custom_fields:
164 |         attrs.pop(field, None)
165 | 
166 | 
167 | def _filter_list_metadata(data: Dict[str, Any]) -> None:
168 |     """Filter list response metadata and pagination links in-place."""
169 |     # Filter metadata
170 |     if "meta" in data:
171 |         meta = data["meta"]
172 |         if "pagination" in meta and isinstance(meta["pagination"], dict):
173 |             pagination = meta["pagination"]
174 |             meta["pagination"] = {
175 |                 "current-page": pagination.get("current-page"),
176 |                 "total-pages": pagination.get("total-pages"),
177 |                 "total-count": pagination.get("total-count"),
178 |             }
179 |         if "status-counts" in meta and isinstance(meta["status-counts"], dict):
180 |             status_counts = meta["status-counts"]
181 |             if "total" in status_counts:
182 |                 meta["status-counts"] = {"total": status_counts["total"]}
183 |             else:
184 |                 meta.pop("status-counts", None)
185 | 
186 |     # Filter pagination links
187 |     if "links" in data and isinstance(data["links"], dict):
188 |         links = data["links"]
189 |         essential_links = {
190 |             k: links[k] for k in ["next", "prev", "first", "last"] if k in links
191 |         }
192 |         data["links"] = essential_links
193 | 
194 | 
195 | def get_response_filter(resource_type: Union[str, ResourceType]) -> Callable:
196 |     """Get the appropriate filter function for a resource type."""
197 | 
198 |     def resource_filter(
199 |         data: Dict[str, Any],
200 |         operation_type: Union[str, OperationType] = OperationType.READ,
201 |     ) -> Dict[str, Any]:
202 |         return filter_response(data, resource_type, operation_type)
203 | 
204 |     return resource_filter
205 | 
206 | 
207 | def should_filter_response(path: str, method: str) -> bool:
208 |     """Determine if a response should be filtered based on the API path and method."""
209 |     # Only filter GET requests
210 |     if method.upper() != "GET":
211 |         return False
212 | 
213 |     # Don't filter log or download endpoints
214 |     skip_terms = ["log", "download", "json-output", "content"]
215 |     return not any(term in path.lower() for term in skip_terms)
216 | 
217 | 
218 | def detect_resource_type(path: str, data: Dict[str, Any]) -> ResourceType:
219 |     """Detect resource type from API path and response data."""
220 |     # Path-based detection
221 |     for pattern, resource_type in PATH_PATTERNS:
222 |         if pattern in path:
223 |             return resource_type
224 | 
225 |     # Data-based fallback
226 |     if isinstance(data, dict) and "data" in data:
227 |         data_item = data["data"]
228 |         if isinstance(data_item, list) and data_item:
229 |             data_type = data_item[0].get("type", "unknown")
230 |         elif isinstance(data_item, dict):
231 |             data_type = data_item.get("type", "unknown")
232 |         else:
233 |             return ResourceType.GENERIC
234 | 
235 |         if data_type in DATA_TYPE_MAP:
236 |             return DATA_TYPE_MAP[data_type]
237 | 
238 |         for resource_type in ResourceType:
239 |             if resource_type.value == data_type:
240 |                 return resource_type
241 | 
242 |     return ResourceType.GENERIC
243 | 
244 | 
245 | def detect_operation_type(path: str, method: str) -> OperationType:
246 |     """Detect operation type from API path and method."""
247 |     if method.upper() == "GET":
248 |         id_prefixes = ["ws-", "run-", "org-", "prj-", "var-"]
249 |         has_resource_id = any(
250 |             segment.startswith(prefix)
251 |             for segment in path.split("/")
252 |             for prefix in id_prefixes
253 |         )
254 |         return OperationType.READ if has_resource_id else OperationType.LIST
255 |     return OperationType.MANAGE
256 | 
```

--------------------------------------------------------------------------------
/docs/conversations/workspace-management-conversation.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Workspace Management - Example Conversations
  2 | 
  3 | This document shows example conversations with Claude using the Terraform Cloud MCP workspace management features.
  4 | 
  5 | ## Listing and Finding Workspaces
  6 | 
  7 | ```
  8 | User: List all my workspaces in "example-org"
  9 | 
 10 | Claude: I'll list all workspaces in the "example-org" organization.
 11 | 
 12 | [Claude uses list_workspaces tool]
 13 | 
 14 | Here are all the workspaces in "example-org":
 15 | 
 16 | 1. **production** - Production environment (Terraform v1.5.2)
 17 |    - Status: Active, Unlocked
 18 |    - Last run: Applied 2 days ago
 19 |    - VCS: Connected to GitHub (main branch)
 20 | 
 21 | 2. **staging** - Staging environment (Terraform v1.5.2)
 22 |    - Status: Active, Unlocked
 23 |    - Last run: Applied 6 hours ago
 24 |    - VCS: Connected to GitHub (develop branch)
 25 | 
 26 | 3. **dev-environment** - Development workspace (Terraform v1.5.3)
 27 |    - Status: Active, Unlocked
 28 |    - Last run: Planning 5 minutes ago
 29 |    - VCS: Connected to GitHub (feature/new-db branch)
 30 | 
 31 | 4. **network-infra** - Network infrastructure (Terraform v1.4.6)
 32 |    - Status: Active, Locked by [email protected]
 33 |    - Last run: Applied 2 weeks ago
 34 |    - VCS: Not connected
 35 | 
 36 | 5. **security-baseline** - Security controls (Terraform v1.5.0)
 37 |    - Status: Active, Unlocked
 38 |    - Last run: Discarded 3 days ago
 39 |    - VCS: Connected to GitHub (main branch)
 40 | 
 41 | User: Find all workspaces in "example-org" with names containing "prod"
 42 | 
 43 | Claude: I'll search for workspaces in the "example-org" organization that have "prod" in their names.
 44 | 
 45 | [Claude uses list_workspaces tool]
 46 | 
 47 | I found the following workspaces in "example-org" with "prod" in their names:
 48 | 
 49 | 1. **production** - Production environment (Terraform v1.5.2)
 50 |    - Status: Active, Unlocked
 51 |    - Last run: Applied 2 days ago
 52 |    - VCS: Connected to GitHub (main branch)
 53 | 
 54 | 2. **products-api** - Products API infrastructure (Terraform v1.5.0)
 55 |    - Status: Active, Unlocked
 56 |    - Last run: Applied 5 days ago
 57 |    - VCS: Connected to GitHub (release/v2 branch)
 58 | 
 59 | 3. **prod-db-cluster** - Production database cluster (Terraform v1.5.1)
 60 |    - Status: Active, Locked by system
 61 |    - Last run: Errored 12 hours ago
 62 |    - VCS: Connected to GitHub (main branch)
 63 | 
 64 | User: List workspaces in "example-org" with the "environment:production" tag
 65 | 
 66 | Claude: I'll find workspaces in "example-org" that have the "environment:production" tag.
 67 | 
 68 | [Claude uses list_workspaces tool]
 69 | 
 70 | Here are the workspaces in "example-org" tagged with "environment:production":
 71 | 
 72 | 1. **production** - Production environment (Terraform v1.5.2)
 73 |    - Tags: environment:production, region:us-west-2
 74 |    - Status: Active, Unlocked
 75 |    - Last run: Applied 2 days ago
 76 | 
 77 | 2. **prod-db-cluster** - Production database cluster (Terraform v1.5.1)
 78 |    - Tags: environment:production, service:database, region:us-west-2
 79 |    - Status: Active, Locked by system
 80 |    - Last run: Errored 12 hours ago
 81 | 
 82 | 3. **frontend-prod** - Production frontend resources (Terraform v1.5.0)
 83 |    - Tags: environment:production, service:frontend, region:us-west-2
 84 |    - Status: Active, Unlocked
 85 |    - Last run: Applied 1 week ago
 86 | 
 87 | 4. **api-gateway-prod** - Production API gateway (Terraform v1.4.6)
 88 |    - Tags: environment:production, service:api, region:us-west-2
 89 |    - Status: Active, Unlocked
 90 |    - Last run: Applied 3 days ago
 91 | 
 92 | ```
 93 | 
 94 | ## Workspace Details and Management
 95 | 
 96 | ```
 97 | User: Get details for the "production" workspace in "example-org"
 98 | 
 99 | Claude: I'll retrieve detailed information about the "production" workspace in "example-org".
100 | 
101 | [Claude uses get_workspace_details tool]
102 | 
103 | Here are the details for the "production" workspace in "example-org":
104 | 
105 | **Basic Information:**
106 | - Name: production
107 | - Description: Production environment for main application
108 | - ID: ws-7H9QJDXpY98V4w2Y
109 | - Created: January 15, 2023
110 | - Updated: May 3, 2024
111 | 
112 | **Terraform Configuration:**
113 | - Version: 1.5.2
114 | - Working Directory: /terraform
115 | - Execution Mode: Remote
116 | - Auto Apply: False
117 | - Terraform State Version: 4
118 | - Resource Count: 143
119 | 
120 | **VCS Integration:**
121 | - Repository: github.com/example-org/main-infrastructure
122 | - Branch: main
123 | - Working Directory: /terraform
124 | - Trigger Prefixes: ["/modules", "/environments/prod"]
125 | 
126 | **Current Status:**
127 | - State: Active
128 | - Lock Status: Unlocked
129 | - Current Run: None
130 | - Last Run: run-bP9xtXmqFoQNfjH7 (Applied 2 days ago)
131 | 
132 | **Tags:**
133 | - environment:production
134 | - region:us-west-2
135 | - team:infrastructure
136 | 
137 | User: Create a new workspace in "example-org" called "staging" with auto-apply enabled
138 | 
139 | Claude: I'll create a new workspace called "staging" in the "example-org" organization with auto-apply enabled.
140 | 
141 | [Claude uses create_workspace tool]
142 | 
143 | I've successfully created the "staging" workspace in "example-org" with auto-apply enabled. Here are the details:
144 | 
145 | **Workspace Details:**
146 | - Name: staging
147 | - Description: Staging environment for testing
148 | - ID: ws-2VcPMzXqD75r8nL9
149 | - Created: Just now
150 | - Terraform Version: 1.5.2
151 | - Working Directory: /terraform/staging
152 | - Execution Mode: Remote
153 | - Auto Apply: Enabled
154 | 
155 | The workspace is now ready to use. Since auto-apply is enabled, any successful plans will automatically be applied without requiring manual approval.
156 | 
157 | User: Update my "staging" workspace to use Terraform version 1.5.0
158 | 
159 | Claude: I'll update the "staging" workspace in "example-org" to use Terraform version 1.5.0.
160 | 
161 | [Claude uses update_workspace tool]
162 | 
163 | I've successfully updated the "staging" workspace to use Terraform version 1.5.0. Here's the confirmation:
164 | 
165 | **Updated Workspace Details:**
166 | - Name: staging
167 | - ID: ws-2VcPMzXqD75r8nL9
168 | - Terraform Version: 1.5.0 (previously 1.5.2)
169 | - Working Directory: /terraform/staging
170 | - Execution Mode: Remote
171 | - Auto Apply: Enabled
172 | 
173 | The change has been applied immediately. Any new runs in this workspace will now use Terraform 1.5.0 instead of 1.5.2.
174 | 
175 | ```
176 | 
177 | ## Workspace Deletion
178 | 
179 | ```
180 | User: Delete my "dev-test" workspace in "example-org"
181 | 
182 | Claude: I'll help you delete the "dev-test" workspace in "example-org". This is a significant action that requires confirmation.
183 | 
184 | [Claude uses delete_workspace tool]
185 | 
186 | **WARNING: Confirmation Required**
187 | 
188 | You've requested to delete the "dev-test" workspace in "example-org". This action:
189 | - Will permanently delete the workspace and all its configurations
190 | - Will delete all workspace variables
191 | - Will delete all state versions and state snapshots
192 | - Cannot be undone
193 | 
194 | To confirm deletion, please explicitly confirm that you want to proceed.
195 | 
196 | User: Yes, please delete the workspace
197 | 
198 | Claude: I'll proceed with deleting the "dev-test" workspace as confirmed.
199 | 
200 | [Claude uses delete_workspace tool]
201 | 
202 | **Deletion Successful**
203 | 
204 | The "dev-test" workspace in "example-org" has been permanently deleted. All associated resources, variables, and state files have been removed.
205 | 
206 | User: Delete my "staging" workspace but only if it's not managing any resources
207 | 
208 | Claude: I'll help you safely delete the "staging" workspace, but only if it's not currently managing any resources.
209 | 
210 | [Claude uses safe_delete_workspace tool]
211 | 
212 | **WARNING: Confirmation Required**
213 | 
214 | You've requested to safely delete the "staging" workspace in "example-org". This operation:
215 | - Will only proceed if the workspace is not managing any resources
216 | - Will fail if there are resources under management
217 | - Will delete all workspace configurations and variables
218 | - Cannot be undone
219 | 
220 | To proceed with the safe deletion, please confirm.
221 | 
222 | User: Yes, proceed with the safe delete
223 | 
224 | Claude: I'll proceed with the safe deletion of the "staging" workspace.
225 | 
226 | [Claude uses safe_delete_workspace tool]
227 | 
228 | **Safe Deletion Successful**
229 | 
230 | The "staging" workspace in "example-org" has been safely deleted. The workspace had no infrastructure resources under management, so the deletion was allowed to proceed.
231 | 
232 | All workspace configurations, variables, and settings have been removed. The operation completed successfully.
233 | 
234 | ```
235 | 
236 | ## Workspace Locking and Unlocking
237 | 
238 | ```
239 | User: Lock my "production" workspace while we do maintenance
240 | 
241 | Claude: I'll lock the "production" workspace to prevent any changes during your maintenance period.
242 | 
243 | [Claude uses lock_workspace tool]
244 | 
245 | **Workspace Locked**
246 | 
247 | I've successfully locked the "production" workspace in "example-org". While locked:
248 | - No new runs can be queued
249 | - Existing runs in progress will continue until completion
250 | - The workspace will remain locked until explicitly unlocked
251 | 
252 | **Lock Details:**
253 | - Workspace: production
254 | - Locked by: Your account ([email protected])
255 | - Reason: Scheduled maintenance in progress
256 | - Locked at: [Current timestamp]
257 | 
258 | The workspace will remain locked until you request it to be unlocked.
259 | 
260 | User: The maintenance is complete, unlock "production" now
261 | 
262 | Claude: I'll unlock the "production" workspace now that maintenance is complete.
263 | 
264 | [Claude uses unlock_workspace tool]
265 | 
266 | **Workspace Unlocked**
267 | 
268 | The "production" workspace in "example-org" has been successfully unlocked. Normal operations can now resume:
269 | - New runs can be queued
270 | - Automatic runs will trigger as configured
271 | - VCS-triggered runs will process normally
272 | 
273 | The workspace is now available for use.
274 | 
275 | User: Someone left "staging" locked and they're out today. Can you force unlock it?
276 | 
277 | Claude: I'll force unlock the "staging" workspace since the person who locked it is unavailable today.
278 | 
279 | [Claude uses force_unlock_workspace tool]
280 | 
281 | **Workspace Force Unlocked**
282 | 
283 | I've successfully force unlocked the "staging" workspace in "example-org". The workspace was previously locked by [email protected] with reason "Testing configuration changes".
284 | 
285 | The force unlock has:
286 | - Removed the lock regardless of who placed it
287 | - Made the workspace available for immediate use
288 | - Allowed new runs to be queued
289 | 
290 | The workspace is now unlocked and available for normal operations. Note that force unlocking should only be done in situations like this where the original locker is unavailable.
291 | ```
```

--------------------------------------------------------------------------------
/terraform_cloud_mcp/models/organizations.py:
--------------------------------------------------------------------------------

```python
  1 | """Organization models for Terraform Cloud API
  2 | 
  3 | This module contains models for Terraform Cloud organization-related requests.
  4 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations
  5 | """
  6 | 
  7 | from typing import Optional, Union
  8 | 
  9 | from pydantic import Field
 10 | 
 11 | from .base import APIRequest, CollaboratorAuthPolicy, ExecutionMode
 12 | 
 13 | 
 14 | class OrganizationDetailsRequest(APIRequest):
 15 |     """Request model for getting organization details.
 16 | 
 17 |     This model is used for the GET /organizations/{name} endpoint. The endpoint
 18 |     returns detailed information about an organization including its name,
 19 |     external ID, created date, and all organization-level settings.
 20 | 
 21 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations#show-an-organization
 22 | 
 23 |     See:
 24 |         docs/models/organization.md for reference
 25 |     """
 26 | 
 27 |     organization: str = Field(
 28 |         ...,
 29 |         # No alias needed as field name matches API field name
 30 |         description="The name of the organization to retrieve details for",
 31 |         min_length=3,
 32 |         pattern=r"^[a-z0-9][-a-z0-9_]*[a-z0-9]$",
 33 |     )
 34 | 
 35 | 
 36 | class OrganizationEntitlementsRequest(APIRequest):
 37 |     """Request model for getting organization entitlements.
 38 | 
 39 |     This model is used for the GET /organizations/{name}/entitlement-set endpoint.
 40 |     The endpoint returns information about which features and capabilities are
 41 |     available to the organization based on its subscription tier.
 42 | 
 43 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations#show-the-entitlement-set
 44 | 
 45 |     See:
 46 |         docs/models/organization.md for reference
 47 |     """
 48 | 
 49 |     organization: str = Field(
 50 |         ...,
 51 |         # No alias needed as field name matches API field name
 52 |         description="The name of the organization to retrieve entitlements for",
 53 |         min_length=3,
 54 |         pattern=r"^[a-z0-9][-a-z0-9_]*[a-z0-9]$",
 55 |     )
 56 | 
 57 | 
 58 | class OrganizationDeleteRequest(APIRequest):
 59 |     """Request model for deleting an organization.
 60 | 
 61 |     This model is used for the DELETE /organizations/{name} endpoint.
 62 |     Deleting an organization is a permanent action and cannot be undone.
 63 |     All workspaces, configurations, and associated resources will be deleted.
 64 | 
 65 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations#delete-an-organization
 66 | 
 67 |     Warning:
 68 |         This is a destructive operation that cannot be undone. Organization names
 69 |         are globally unique and cannot be recreated with the same name later.
 70 | 
 71 |     See:
 72 |         docs/models/organization.md for reference
 73 |     """
 74 | 
 75 |     organization: str = Field(
 76 |         ...,
 77 |         # No alias needed as field name matches API field name
 78 |         description="The name of the organization to delete",
 79 |         min_length=3,
 80 |         pattern=r"^[a-z0-9][-a-z0-9_]*[a-z0-9]$",
 81 |     )
 82 | 
 83 | 
 84 | class OrganizationListRequest(APIRequest):
 85 |     """Request parameters for listing organizations.
 86 | 
 87 |     These parameters map to the query parameters in the organizations API.
 88 |     The endpoint returns a paginated list of organizations that the authenticated
 89 |     user has access to, along with their details.
 90 | 
 91 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations#list-organizations
 92 | 
 93 |     See:
 94 |         docs/models/organization.md for reference
 95 |     """
 96 | 
 97 |     page_number: Optional[int] = Field(1, ge=1, description="Page number to fetch")
 98 |     page_size: Optional[int] = Field(
 99 |         20, ge=1, le=100, description="Number of results per page"
100 |     )
101 |     q: Optional[str] = Field(
102 |         None, description="Search query for name and email", max_length=100
103 |     )
104 |     query_email: Optional[str] = Field(
105 |         None, description="Search query for email", max_length=100
106 |     )
107 |     query_name: Optional[str] = Field(
108 |         None, description="Search query for name", max_length=100
109 |     )
110 | 
111 | 
112 | class BaseOrganizationRequest(APIRequest):
113 |     """Base class for organization create and update requests with common fields.
114 | 
115 |     This includes all fields that are commonly used in request payloads for the organization
116 |     creation and update APIs.
117 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations
118 | 
119 |     Note:
120 |         This class inherits model_config from APIRequest -> BaseModelConfig
121 | 
122 |     See:
123 |         docs/models/organization.md for fields and usage examples
124 |     """
125 | 
126 |     # Fields common to both create and update requests with API defaults from docs
127 |     name: Optional[str] = Field(
128 |         None,
129 |         # No alias needed as field name matches API field name
130 |         description="Name of the organization",
131 |         min_length=3,
132 |         pattern=r"^[a-z0-9][-a-z0-9_]*[a-z0-9]$",
133 |     )
134 |     email: Optional[str] = Field(
135 |         None,
136 |         # No alias needed as field name matches API field name
137 |         description="Admin email address",
138 |         pattern=r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
139 |     )
140 |     session_timeout: Optional[int] = Field(
141 |         20160,
142 |         alias="session-timeout",
143 |         description="Session timeout after inactivity in minutes",
144 |         ge=1,
145 |         le=43200,  # 30 days in minutes
146 |     )
147 |     session_remember: Optional[int] = Field(
148 |         20160,
149 |         alias="session-remember",
150 |         description="Session expiration in minutes",
151 |         ge=1,
152 |         le=43200,  # 30 days in minutes
153 |     )
154 |     collaborator_auth_policy: Optional[Union[str, CollaboratorAuthPolicy]] = Field(
155 |         CollaboratorAuthPolicy.PASSWORD,
156 |         alias="collaborator-auth-policy",
157 |         description="Authentication policy",
158 |     )
159 |     cost_estimation_enabled: Optional[bool] = Field(
160 |         False,
161 |         alias="cost-estimation-enabled",
162 |         description="Whether cost estimation is enabled for all workspaces",
163 |     )
164 |     send_passing_statuses_for_untriggered_speculative_plans: Optional[bool] = Field(
165 |         False,
166 |         alias="send-passing-statuses-for-untriggered-speculative-plans",
167 |         description="Whether to send VCS status updates for untriggered plans",
168 |     )
169 |     aggregated_commit_status_enabled: Optional[bool] = Field(
170 |         True,
171 |         alias="aggregated-commit-status-enabled",
172 |         description="Whether to aggregate VCS status updates",
173 |     )
174 |     speculative_plan_management_enabled: Optional[bool] = Field(
175 |         True,
176 |         alias="speculative-plan-management-enabled",
177 |         description="Whether to enable automatic cancellation of plan-only runs",
178 |     )
179 |     owners_team_saml_role_id: Optional[str] = Field(
180 |         None,
181 |         alias="owners-team-saml-role-id",
182 |         description="SAML only - the name of the 'owners' team",
183 |     )
184 |     assessments_enforced: Optional[bool] = Field(
185 |         False,
186 |         alias="assessments-enforced",
187 |         description="Whether to compel health assessments for all eligible workspaces",
188 |     )
189 |     allow_force_delete_workspaces: Optional[bool] = Field(
190 |         False,
191 |         alias="allow-force-delete-workspaces",
192 |         description="Whether workspace admins can delete workspaces with resources",
193 |     )
194 |     default_execution_mode: Optional[Union[str, ExecutionMode]] = Field(
195 |         ExecutionMode.REMOTE,
196 |         alias="default-execution-mode",
197 |         description="Default execution mode",
198 |     )
199 |     default_agent_pool_id: Optional[str] = Field(
200 |         None,
201 |         alias="default-agent-pool-id",
202 |         description="The ID of the agent pool (required when default_execution_mode is 'agent')",
203 |     )
204 | 
205 | 
206 | class OrganizationCreateRequest(BaseOrganizationRequest):
207 |     """Request model for creating a Terraform Cloud organization.
208 | 
209 |     Validates and structures the request according to the Terraform Cloud API
210 |     requirements for creating organizations.
211 | 
212 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations#create-an-organization
213 | 
214 |     Note:
215 |         This inherits all configuration fields from BaseOrganizationRequest
216 |         while making name and email required.
217 | 
218 |     See:
219 |         docs/models/organization.md for reference
220 |     """
221 | 
222 |     # Override name and email to make them required for creation
223 |     name: str = Field(..., description="Name of the organization")
224 |     email: str = Field(..., description="Admin email address")
225 | 
226 | 
227 | class OrganizationUpdateRequest(BaseOrganizationRequest):
228 |     """Request model for updating a Terraform Cloud organization.
229 | 
230 |     Validates and structures the request according to the Terraform Cloud API
231 |     requirements for updating organizations. All fields are optional.
232 | 
233 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations#update-an-organization
234 | 
235 |     Note:
236 |         This inherits all configuration fields from BaseOrganizationRequest
237 |         and adds a required organization field for routing.
238 | 
239 |     See:
240 |         docs/models/organization.md for reference
241 |     """
242 | 
243 |     # Add organization field which is required for updates but not part of the attributes
244 |     organization: str = Field(
245 |         ...,
246 |         # No alias needed as field name matches API field name
247 |         description="The name of the organization to update",
248 |     )
249 | 
250 | 
251 | class OrganizationParams(BaseOrganizationRequest):
252 |     """Parameters for organization operations without routing fields.
253 | 
254 |     This model provides all optional parameters that can be used when creating or updating
255 |     organizations, reusing the field definitions from BaseOrganizationRequest.
256 | 
257 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/organizations
258 | 
259 |     Note:
260 |         All fields are inherited from BaseOrganizationRequest.
261 | 
262 |     See:
263 |         docs/models/organization.md for reference
264 |     """
265 | 
266 |     # Inherits model_config and all fields from BaseOrganizationRequest
267 | 
268 | 
269 | # Response handling is implemented through raw dictionaries
270 | 
```

--------------------------------------------------------------------------------
/docs/models/run.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Run Models
  2 | 
  3 | This document describes the data models used for run operations in Terraform Cloud.
  4 | 
  5 | ## Overview
  6 | 
  7 | Run models provide structure and validation for initiating and managing runs in Terraform Cloud. These models define run configuration options, variables, targeting, and behavior settings. Runs represent the execution of Terraform plans and applies, serving as the primary method for making infrastructure changes.
  8 | 
  9 | ## Models Reference
 10 | 
 11 | ### RunVariable
 12 | 
 13 | **Type:** Object
 14 | 
 15 | **Description:** Defines a variable to be included with a specific run. Run variables override workspace variables for the duration of the run.
 16 | 
 17 | **Fields:**
 18 | - `key` (string, required): The variable name (max length: 128)
 19 | - `value` (string, required): The variable value (max length: 256)
 20 | 
 21 | **JSON representation:**
 22 | ```json
 23 | {
 24 |   "key": "environment",
 25 |   "value": "production"
 26 | }
 27 | ```
 28 | 
 29 | **Usage Context:**
 30 | Run variables provide a way to override workspace variables temporarily for a specific run without changing the workspace configuration. This is useful for testing changes with different variable values or handling one-off scenarios.
 31 | 
 32 | ### RunOperation
 33 | 
 34 | **Type:** Enum (string)
 35 | 
 36 | **Description:** Describes the type of operation being performed by a run.
 37 | 
 38 | **Values:**
 39 | - `plan`: Standard planning operation
 40 | - `plan_destroy`: Planning a destroy operation
 41 | - `apply`: Standard apply operation
 42 | - `destroy`: Destroying resources operation
 43 | 
 44 | **Usage Context:**
 45 | Used for filtering runs and determining the type of operation being performed.
 46 | 
 47 | ### RunSource
 48 | 
 49 | **Type:** Enum (string)
 50 | 
 51 | **Description:** Indicates the origin that initiated the run.
 52 | 
 53 | **Values:**
 54 | - `api`: Run was created via the API
 55 | - `cli`: Run was created using Terraform CLI
 56 | - `ui`: Run was created through the web UI
 57 | - `vcs`: Run was triggered by a VCS change
 58 | - `run_trigger`: Run was triggered by another workspace's changes
 59 | 
 60 | **Usage Context:**
 61 | Useful for identifying how a run was created and for filtering runs by their origin.
 62 | 
 63 | ### RunStatusGroup
 64 | 
 65 | **Type:** Enum (string)
 66 | 
 67 | **Description:** Categorizes runs into logical groupings based on their current state.
 68 | 
 69 | **Values:**
 70 | - `pending`: Runs that haven't completed their execution (includes planning, applying)
 71 | - `completed`: Runs that have finished execution successfully (planned, applied, etc.)
 72 | - `failed`: Runs that have encountered errors or been canceled
 73 | - `discarded`: Runs whose changes were not applied
 74 | 
 75 | **Usage Context:**
 76 | Provides a higher-level categorization of run statuses for filtering and reporting.
 77 | 
 78 | ### RunParams
 79 | 
 80 | **Type:** Object
 81 | 
 82 | **Description:** Parameters for run operations. Used to specify configuration options when creating a run.
 83 | 
 84 | **Fields:**
 85 | - `message` (string, optional): Description of the run's purpose
 86 | - `is_destroy` (boolean, optional): Whether to destroy all resources (default: false)
 87 | - `auto_apply` (boolean, optional): Whether to auto-apply after successful plan
 88 | - `refresh` (boolean, optional): Whether to refresh state before planning (default: true)
 89 | - `refresh_only` (boolean, optional): Only refresh state without planning changes (default: false)
 90 | - `plan_only` (boolean, optional): Create speculative plan without applying (default: false)
 91 | - `allow_empty_apply` (boolean, optional): Allow applies with no changes (default: false)
 92 | - `target_addrs` (array, optional): List of resource addresses to target
 93 | - `replace_addrs` (array, optional): List of resource addresses to force replacement
 94 | - `variables` (array, optional): Run-specific variables that override workspace variables
 95 | - `terraform_version` (string, optional): Specific Terraform version for this run
 96 | - `save_plan` (boolean, optional): Save the plan for later execution (default: false)
 97 | - `debugging_mode` (boolean, optional): Enable extended debug logging (default: false)
 98 | - `allow_config_generation` (boolean, optional): Allow generating config for imports (default: false)
 99 | 
100 | **JSON representation:**
101 | ```json
102 | {
103 |   "data": {
104 |     "type": "runs",
105 |     "attributes": {
106 |       "message": "Deploy infrastructure changes",
107 |       "plan-only": false,
108 |       "is-destroy": false,
109 |       "refresh": true,
110 |       "auto-apply": false,
111 |       "target-addrs": ["module.network", "aws_instance.web_servers"],
112 |       "replace-addrs": ["module.database.aws_db_instance.main"],
113 |       "variables": [
114 |         {"key": "environment", "value": "production"},
115 |         {"key": "region", "value": "us-west-2"}
116 |       ]
117 |     },
118 |     "relationships": {
119 |       "workspace": {
120 |         "data": {
121 |           "id": "ws-example123",
122 |           "type": "workspaces"
123 |         }
124 |       }
125 |     }
126 |   }
127 | }
128 | ```
129 | 
130 | **Validation Rules:**
131 | - When using `plan_only`, the run will not proceed to apply phase
132 | - If `is_destroy` is true, the run will create a plan to destroy all resources
133 | - `terraform_version` can only be specified for plan-only runs
134 | - `replace_addrs` and `target_addrs` must be valid resource addresses
135 | 
136 | ### RunStatus
137 | 
138 | **Type:** Enum (string)
139 | 
140 | **Description:** Represents the possible states of a run during its lifecycle.
141 | 
142 | **Values:**
143 | - `pending`: Not yet started
144 | - `planning`: Currently running the plan phase
145 | - `planned`: Plan phase completed successfully
146 | - `cost_estimating`: Cost estimate in progress
147 | - `cost_estimated`: Cost estimate completed
148 | - `policy_checking`: Policy check in progress
149 | - `policy_override`: Policy check soft-failed, requires override
150 | - `policy_checked`: Policy check passed
151 | - `confirmed`: Plan confirmed for apply
152 | - `planned_and_finished`: Plan completed, no changes required
153 | - `applying`: Currently applying changes
154 | - `applied`: Apply phase completed successfully
155 | - `discarded`: Discarded and not applied
156 | - `errored`: Encountered an error during the run
157 | - `canceled`: Was canceled during execution
158 | - `force_canceled`: Was forcibly canceled during execution
159 | 
160 | **Usage Context:**
161 | Used to determine the current phase and state of a run and what actions can be taken on it. For example:
162 | - Only runs in `planned` status can be applied
163 | - Only runs in `planning`, `applying`, or other active states can be canceled
164 | 
165 | ### RunCreateRequest
166 | 
167 | **Type:** Request Validation Model
168 | 
169 | **Description:** Used to validate parameters for creating a run.
170 | 
171 | **Fields:**
172 | - `workspace_id` (string, required): The ID of the workspace to create a run in
173 | - `params` (RunParams, optional): Configuration options for the run
174 | 
175 | **Used by:**
176 | - `create_run` tool function to validate run creation parameters
177 | 
178 | ### RunDetailsRequest
179 | 
180 | **Type:** Request Validation Model
181 | 
182 | **Description:** Used to validate parameters for retrieving run details.
183 | 
184 | **Fields:**
185 | - `run_id` (string, required): The ID of the run to retrieve details for
186 |   - Format: Must match pattern "run-[a-zA-Z0-9]{16}"
187 |   - Example: "run-AbCdEfGhIjKlMnOp"
188 | 
189 | **Validation Rules:**
190 | - Run ID must start with "run-" prefix
191 | - Must contain exactly 16 alphanumeric characters after the prefix
192 | 
193 | ### RunActionRequest
194 | 
195 | **Type:** Request Validation Model
196 | 
197 | **Description:** Used to validate parameters for performing actions on a run.
198 | 
199 | **Fields:**
200 | - `run_id` (string, required): The ID of the run to perform an action on
201 | - `comment` (string, optional): An optional explanation for the action
202 | 
203 | **Used by:**
204 | - `apply_run`, `discard_run`, `cancel_run`, `force_cancel_run` tool functions
205 | 
206 | ### RunListRequest
207 | 
208 | **Type:** Request Validation Model
209 | 
210 | **Description:** Used to validate parameters for listing runs in a workspace.
211 | 
212 | **Fields:**
213 | - `workspace_id` (string, required): The workspace ID to list runs for
214 | - `page_number` (int, optional): Page number to fetch (default: 1)
215 | - `page_size` (int, optional): Number of results per page (default: 20)
216 | - Filter fields for more specific results:
217 |   - `filter_operation`, `filter_status`, `filter_source`, `filter_status_group`
218 | 
219 | **Used by:**
220 | - `list_runs_in_workspace` tool function to validate listing parameters
221 | 
222 | ## API Response Structure
223 | 
224 | ### Run Details Response
225 | 
226 | ```json
227 | {
228 |   "data": {
229 |     "id": "run-CKJhKBXrxZuc9WLS",
230 |     "type": "runs",
231 |     "attributes": {
232 |       "status": "planned",
233 |       "message": "Deploy infrastructure changes",
234 |       "has-changes": true,
235 |       "created-at": "2023-05-05T15:45:22Z",
236 |       "is-destroy": false,
237 |       "source": "tfe-cli",
238 |       "status-timestamps": {
239 |         "planned-at": "2023-05-05T15:46:02Z"
240 |       }
241 |     },
242 |     "relationships": {
243 |       "workspace": {
244 |         "data": {
245 |           "id": "ws-SihZTyXKfNXUWuUa",
246 |           "type": "workspaces"
247 |         }
248 |       },
249 |       "plan": {
250 |         "data": {
251 |           "id": "plan-j9yycwFSJ2Mn8wuC",
252 |           "type": "plans"
253 |         }
254 |       },
255 |       "cost-estimate": {
256 |         "data": {
257 |           "id": "ce-BPvFFrYCqRV6qVBK",
258 |           "type": "cost-estimates"
259 |         }
260 |       }
261 |     },
262 |     "links": {
263 |       "self": "/api/v2/runs/run-CKJhKBXrxZuc9WLS"
264 |     }
265 |   }
266 | }
267 | ```
268 | 
269 | ### List Runs Response
270 | 
271 | ```json
272 | {
273 |   "data": [
274 |     {
275 |       "id": "run-CKJhKBXrxZuc9WLS",
276 |       "type": "runs",
277 |       "attributes": {
278 |         "status": "applied",
279 |         "message": "Weekly infrastructure update",
280 |         "has-changes": true,
281 |         "created-at": "2023-05-05T15:45:22Z",
282 |         "is-destroy": false,
283 |         "source": "tfe-cli"
284 |       }
285 |     },
286 |     {
287 |       "id": "run-DKJhKBXrxZuc9WLA",
288 |       "type": "runs",
289 |       "attributes": {
290 |         "status": "planned",
291 |         "message": "Update database configuration",
292 |         "has-changes": true,
293 |         "created-at": "2023-05-06T09:12:34Z",
294 |         "is-destroy": false,
295 |         "source": "api"
296 |       }
297 |     }
298 |   ],
299 |   "meta": {
300 |     "pagination": {
301 |       "current-page": 1,
302 |       "page-size": 20,
303 |       "prev-page": null,
304 |       "next-page": null,
305 |       "total-pages": 1,
306 |       "total-count": 2
307 |     }
308 |   }
309 | }
310 | ```
311 | 
312 | ## Related Resources
313 | 
314 | - [Run Tools](../tools/run.md)
315 | - [Plan Models](plan.md)
316 | - [Apply Models](apply.md)
317 | - [Cost Estimate Models](cost_estimate.md)
318 | - [Terraform Cloud API - Runs](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/run)
```

--------------------------------------------------------------------------------
/docs/conversations/variables-conversation.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Variables Management - Example Conversations
  2 | 
  3 | This document shows example conversations with Claude using the Terraform Cloud MCP variable management features.
  4 | 
  5 | ## Setting Up Workspace Variables
  6 | 
  7 | ```
  8 | User: I need to set up variables for my new web-app workspace. Can you first show me what variables already exist, then help me add some basic ones?
  9 | 
 10 | Claude: I'll check the existing variables in your web-app workspace and then help you add the ones you need.
 11 | 
 12 | [Claude uses list_workspace_variables tool]
 13 | 
 14 | I can see your workspace currently has no variables configured. Let me help you set up some common variables for a web application.
 15 | 
 16 | First, I'll add a Terraform variable for the environment:
 17 | 
 18 | [Claude uses create_workspace_variable tool]
 19 | 
 20 | I've created a Terraform variable called "environment" with the value "development" to help with resource naming.
 21 | 
 22 | Now let me add an environment variable for the application port:
 23 | 
 24 | [Claude uses create_workspace_variable tool]
 25 | 
 26 | I've added an environment variable "APP_PORT" set to "3000" for your application.
 27 | 
 28 | Finally, let me add a sensitive variable for database credentials:
 29 | 
 30 | [Claude uses create_workspace_variable tool]
 31 | 
 32 | I've created a sensitive environment variable "DB_PASSWORD" for your database connection. The value is hidden for security.
 33 | 
 34 | Your workspace now has three variables configured:
 35 | - **environment** (terraform): "development" - Used for resource naming
 36 | - **APP_PORT** (env): "3000" - Application port number  
 37 | - **DB_PASSWORD** (env): [hidden] - Database password (sensitive)
 38 | 
 39 | User: I need to update the environment variable from "development" to "staging" and make the database password more secure.
 40 | 
 41 | Claude: I'll help you update both of those variables. Let me modify the environment variable first, then update the database password.
 42 | 
 43 | [Claude uses update_workspace_variable tool]
 44 | 
 45 | I've updated the environment variable from "development" to "staging" and updated the description to reflect the change.
 46 | 
 47 | [Claude uses update_workspace_variable tool]
 48 | 
 49 | I've also updated the database password with a more secure value while keeping it marked as sensitive.
 50 | 
 51 | Both variables have been successfully updated:
 52 | - **environment**: Now set to "staging"
 53 | - **DB_PASSWORD**: Updated with a stronger password (value remains hidden)
 54 | ```
 55 | 
 56 | ## Variable Sets Management
 57 | 
 58 | ```
 59 | User: I want to create a variable set for AWS configuration that I can share across multiple workspaces. It should include region, instance type, and some common tags.
 60 | 
 61 | Claude: I'll help you create an AWS configuration variable set that can be shared across your workspaces. This will ensure consistent configuration across your infrastructure.
 62 | 
 63 | [Claude uses create_variable_set tool]
 64 | 
 65 | I've created a variable set called "aws-common-config" with priority enabled, which means these variables will override any workspace-level variables with the same names.
 66 | 
 67 | Now let me add the AWS configuration variables to this set:
 68 | 
 69 | [Claude uses create_variable_in_variable_set tool]
 70 | 
 71 | I've added the AWS region variable set to "us-west-2".
 72 | 
 73 | [Claude uses create_variable_in_variable_set tool]
 74 | 
 75 | I've added the default instance type as "t3.micro".
 76 | 
 77 | [Claude uses create_variable_in_variable_set tool]
 78 | 
 79 | I've added common tags as an HCL variable that includes Environment, ManagedBy, and Team tags.
 80 | 
 81 | Your AWS configuration variable set is now ready with:
 82 | - **aws_region**: "us-west-2"
 83 | - **instance_type**: "t3.micro"  
 84 | - **common_tags**: HCL object with Environment, ManagedBy, and Team tags
 85 | 
 86 | Since this variable set has priority enabled, these variables will take precedence over any workspace-level variables with the same names.
 87 | 
 88 | User: I want to assign the AWS variable set to my web-app and api-service workspaces, and also assign it to my entire "production" project.
 89 | 
 90 | Claude: I'll assign the AWS configuration variable set to both your specific workspaces and the entire production project. This will ensure consistent AWS configuration across your infrastructure.
 91 | 
 92 | [Claude uses assign_variable_set_to_workspaces tool]
 93 | 
 94 | I've assigned the AWS variable set to your web-app and api-service workspaces.
 95 | 
 96 | [Claude uses assign_variable_set_to_projects tool]
 97 | 
 98 | I've also assigned the variable set to your entire production project.
 99 | 
100 | The AWS configuration variable set is now active in:
101 | - **web-app** and **api-service** workspaces directly
102 | - All workspaces within the **production** project
103 | 
104 | Any new workspaces added to the production project will automatically inherit these AWS variables.
105 | ```
106 | 
107 | ## Managing Sensitive Variables
108 | 
109 | ```
110 | User: I need to add some API keys and database credentials to my workspace. How should I handle these sensitive values?
111 | 
112 | Claude: For sensitive data like API keys and credentials, I'll make sure to mark them as sensitive so their values are hidden in the UI and API responses. This is crucial for security.
113 | 
114 | Let me add these sensitive variables for you:
115 | 
116 | [Claude uses create_workspace_variable tool]
117 | 
118 | I've added your Stripe API secret key as a sensitive environment variable. The value is now hidden from the UI and logs.
119 | 
120 | [Claude uses create_workspace_variable tool]
121 | 
122 | I've added the database connection string as a sensitive environment variable as well.
123 | 
124 | [Claude uses create_workspace_variable tool]
125 | 
126 | I've also added your OAuth client secret as a sensitive environment variable.
127 | 
128 | All three sensitive variables have been created:
129 | - **STRIPE_SECRET_KEY** (env, sensitive): Your payment processing key
130 | - **DATABASE_URL** (env, sensitive): Database connection string  
131 | - **OAUTH_CLIENT_SECRET** (env, sensitive): OAuth application secret
132 | 
133 | These values are now secured and won't be visible in the Terraform Cloud UI or appear in logs. They'll only be available to your Terraform runs as environment variables.
134 | 
135 | User: How can I see what variables are available across all my variable sets?
136 | 
137 | Claude: I'll help you get an overview of your variable sets and their contents. Let me start by listing all your variable sets.
138 | 
139 | [Claude uses list_variable_sets tool]
140 | 
141 | You have several variable sets configured:
142 | 
143 | 1. **aws-common-config** - Common AWS configuration (priority enabled)
144 | 2. **production-secrets** - Production environment secrets (priority enabled)  
145 | 3. **development-config** - Development environment variables (global)
146 | 
147 | Let me show you what variables are in each set:
148 | 
149 | [Claude uses list_variables_in_variable_set tool]
150 | 
151 | **aws-common-config** contains:
152 | - aws_region: "us-west-2"
153 | - instance_type: "t3.micro"
154 | - common_tags: HCL object with standard tags
155 | 
156 | [Claude uses list_variables_in_variable_set tool]
157 | 
158 | **production-secrets** contains:
159 | - DATABASE_URL: [sensitive] - Production database connection
160 | - API_KEY: [sensitive] - Production API key
161 | - REDIS_URL: [sensitive] - Redis connection string
162 | 
163 | [Claude uses list_variables_in_variable_set tool]
164 | 
165 | **development-config** contains:
166 | - DEBUG_MODE: "true"
167 | - LOG_LEVEL: "debug"
168 | - MOCK_SERVICES: "true"
169 | 
170 | This gives you a complete view of your variable organization across different environments and purposes.
171 | ```
172 | 
173 | ## Variable Set Organization Strategy
174 | 
175 | ```
176 | User: What's the best way to organize variables for development, staging, and production environments?
177 | 
178 | Claude: Let me show you an effective variable organization strategy and help you see how your current setup compares to best practices.
179 | 
180 | [Claude uses list_variable_sets tool]
181 | 
182 | Looking at your current variable sets, I can recommend an organization strategy that follows best practices:
183 | 
184 | **Environment-specific variable sets:**
185 | - Create separate variable sets for each environment (dev, staging, prod)
186 | - Use `global=false` and assign to specific projects/workspaces
187 | - Include environment-specific values like database URLs, API endpoints
188 | 
189 | **Common configuration variable sets:**
190 | - Shared provider configuration (like your AWS set)
191 | - Common tags and naming conventions  
192 | - Use `priority=true` to ensure consistency
193 | 
194 | **Application-specific variables:**
195 | - Keep at workspace level for unique configurations
196 | - Use for application-specific secrets and settings
197 | 
198 | Based on your current setup, you're already following good practices with your "aws-common-config" set. Here's what I'd recommend:
199 | 
200 | 1. **Keep your AWS common config** - It's well structured with priority enabled
201 | 2. **Create environment-specific sets** - Separate sets for dev/staging/prod environments
202 | 3. **Use project assignments** - Assign environment sets to corresponding projects
203 | 4. **Workspace-level for unique values** - Keep application-specific variables at workspace level
204 | 
205 | This approach provides:
206 | - Clear separation of concerns
207 | - Easy environment promotion  
208 | - Consistent infrastructure configuration
209 | - Secure handling of sensitive data
210 | 
211 | Would you like me to help you implement any of these organizational improvements?
212 | ```
213 | 
214 | ## Variable Cleanup and Maintenance
215 | 
216 | ```
217 | User: I need to clean up some old variables from my AWS variable set and remove a deprecated variable set entirely.
218 | 
219 | Claude: I'll help you clean up those unused variables and remove the deprecated variable set. Since these are delete operations, they'll permanently remove the data.
220 | 
221 | Let me start by removing the unused variable from your AWS variable set:
222 | 
223 | [Claude uses delete_variable_from_variable_set tool]
224 | 
225 | I've removed the old variable from your AWS variable set. The variable is now gone from all workspaces that use this variable set.
226 | 
227 | Now let me remove the deprecated variable set entirely:
228 | 
229 | [Claude uses delete_variable_set tool]
230 | 
231 | The deprecated variable set has been completely removed. This action:
232 | - Deleted all variables within the set
233 | - Unassigned it from all workspaces and projects  
234 | - Cannot be undone
235 | 
236 | Your variable management is now cleaned up:
237 | - Unused variable removed from AWS configuration set
238 | - Deprecated variable set completely deleted
239 | - All affected workspaces updated automatically
240 | 
241 | The cleanup is complete and your variable organization is now more streamlined.
242 | ```
```

--------------------------------------------------------------------------------
/docs/models/workspace.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Workspace Models
  2 | 
  3 | This document describes the data models used for workspace operations in Terraform Cloud.
  4 | 
  5 | ## Overview
  6 | 
  7 | Workspace models provide structure and validation for interacting with the Terraform Cloud Workspaces API. These models define workspace configuration options, VCS repository settings, and execution modes. Workspaces serve as the primary organizational unit in Terraform Cloud, containing Terraform configurations, state files, variables, and run history for managing specific infrastructure resources.
  8 | 
  9 | ## Models Reference
 10 | 
 11 | ### ExecutionMode
 12 | 
 13 | **Type:** Enum (string)
 14 | 
 15 | **Description:** Defines how Terraform operations are executed.
 16 | 
 17 | **Values:**
 18 | - `remote`: Terraform runs on Terraform Cloud's infrastructure
 19 | - `local`: Terraform runs on your local machine
 20 | - `agent`: Terraform runs on your own infrastructure using an agent
 21 | 
 22 | **JSON representation:**
 23 | ```json
 24 | {
 25 |   "execution-mode": "remote"
 26 | }
 27 | ```
 28 | 
 29 | **Usage Context:**
 30 | The execution mode determines where Terraform commands are run when triggered through the API, UI, or VCS. Different execution modes offer trade-offs between convenience, security, and integration with existing workflows.
 31 | 
 32 | **Notes:**
 33 | - Default value is `remote`
 34 | - When using `agent` mode, you must also specify an `agent-pool-id`
 35 | - The `local` mode is typically used for CLI-driven workflows
 36 | 
 37 | ### VcsRepoConfig
 38 | 
 39 | **Type:** Object
 40 | 
 41 | **Description:** Version control system repository configuration for a workspace.
 42 | 
 43 | **Fields:**
 44 | - `branch` (string, optional): The repository branch that Terraform executes from
 45 | - `identifier` (string, optional): Repository reference in the format `:org/:repo`
 46 | - `ingress_submodules` (boolean, optional): Whether to fetch submodules when cloning
 47 | - `oauth_token_id` (string, optional): VCS OAuth connection and token ID
 48 | - `github_app_installation_id` (string, optional): GitHub App Installation ID
 49 | - `tags_regex` (string, optional): Regex pattern to match Git tags
 50 | 
 51 | **JSON representation:**
 52 | ```json
 53 | {
 54 |   "vcs-repo": {
 55 |     "branch": "main",
 56 |     "identifier": "my-org/my-repo",
 57 |     "ingress-submodules": true,
 58 |     "oauth-token-id": "ot-1234abcd"
 59 |   }
 60 | }
 61 | ```
 62 | 
 63 | **Usage Context:**
 64 | Configuring VCS integration allows Terraform Cloud to automatically queue runs when changes are pushed to the linked repository. The workspace will use the Terraform configuration files from the repository at the specified branch.
 65 | 
 66 | ### WorkspaceParams
 67 | 
 68 | **Type:** Object
 69 | 
 70 | **Description:** Parameters for workspace operations without routing fields. Used to specify configuration parameters for creating or updating workspaces.
 71 | 
 72 | **Fields:**
 73 | - `name` (string, optional): Name of the workspace
 74 | - `description` (string, optional): Human-readable description
 75 | - `execution_mode` (string, optional): How operations are executed (remote, local, agent)
 76 | - `agent_pool_id` (string, optional): Agent pool ID (required when execution_mode=agent)
 77 | - `assessments_enabled` (boolean, optional): Whether to perform health assessments
 78 | - `auto_apply` (boolean, optional): Whether to auto-apply successful plans from VCS/CLI
 79 | - `auto_apply_run_trigger` (boolean, optional): Whether to auto-apply changes from run triggers
 80 | - `auto_destroy_at` (string, optional): Timestamp when the next destroy run will occur
 81 | - `auto_destroy_activity_duration` (string, optional): Auto-destroy duration based on inactivity
 82 | - `file_triggers_enabled` (boolean, optional): Whether to filter runs based on file paths
 83 | - `working_directory` (string, optional): Directory to execute commands in
 84 | - `speculative_enabled` (boolean, optional): Whether to allow speculative plans
 85 | - `terraform_version` (string, optional): Version of Terraform to use (default: latest)
 86 | - `global_remote_state` (boolean, optional): Allow all workspaces to access this state
 87 | - `vcs_repo` (VcsRepoConfig, optional): VCS repository configuration
 88 | - `allow_destroy_plan` (boolean, optional): Allow destruction plans (default: true)
 89 | - `queue_all_runs` (boolean, optional): Whether runs should be queued immediately
 90 | - `source_name` (string, optional): Where workspace settings originated
 91 | - `source_url` (string, optional): URL to origin source
 92 | - `trigger_prefixes` (array, optional): List of paths that trigger runs
 93 | - `trigger_patterns` (array, optional): List of glob patterns that trigger runs
 94 | - `setting_overwrites` (object, optional): Attributes with organization-level defaults
 95 | 
 96 | **JSON representation:**
 97 | ```json
 98 | {
 99 |   "data": {
100 |     "type": "workspaces",
101 |     "attributes": {
102 |       "name": "my-workspace",
103 |       "description": "Example workspace for terraform configurations",
104 |       "terraform-version": "1.5.0",
105 |       "working-directory": "terraform/",
106 |       "auto-apply": true,
107 |       "file-triggers-enabled": true,
108 |       "trigger-patterns": ["**/*.tf", "*.tfvars"],
109 |       "vcs-repo": {
110 |         "identifier": "organization/repo-name",
111 |         "oauth-token-id": "ot-1234abcd",
112 |         "branch": "main"
113 |       }
114 |     }
115 |   }
116 | }
117 | ```
118 | 
119 | **Validation Rules:**
120 | - Workspace names must be unique within an organization
121 | - When using `agent` execution mode, `agent_pool_id` must be provided
122 | - `terraform_version` must be a valid Terraform version string
123 | - `trigger_patterns` and `trigger_prefixes` can only be used when `file_triggers_enabled` is true
124 | 
125 | ### WorkspaceCreateRequest
126 | 
127 | **Type:** Request Validation Model
128 | 
129 | **Description:** Used to validate parameters for creating a workspace.
130 | 
131 | **Fields:**
132 | - `organization` (string, required): The organization name
133 | - `name` (string, required): The name for the new workspace
134 | - `params` (WorkspaceParams, optional): Additional configuration options
135 | 
136 | **Used by:**
137 | - `create_workspace` tool function to validate workspace creation parameters
138 | 
139 | ### WorkspaceUpdateRequest
140 | 
141 | **Type:** Request Validation Model
142 | 
143 | **Description:** Used to validate parameters for updating a workspace.
144 | 
145 | **Fields:**
146 | - `organization` (string, required): The organization name
147 | - `workspace_name` (string, required): The name of the workspace to update
148 | - `params` (WorkspaceParams, optional): Settings to update
149 | 
150 | **Used by:**
151 | - `update_workspace` tool function to validate workspace update parameters
152 | 
153 | ### WorkspaceListRequest
154 | 
155 | **Type:** Request Validation Model
156 | 
157 | **Description:** Parameters for listing workspaces in an organization.
158 | 
159 | **Fields:**
160 | - `organization` (string, required): The name of the organization to list workspaces from
161 | - `page_number` (integer, optional): Page number to fetch (default: 1)
162 | - `page_size` (integer, optional): Number of results per page (default: 20, max: 100)
163 | - `search` (string, optional): Substring to search for in workspace names
164 | 
165 | **Usage Context:**
166 | Used to retrieve a paginated list of workspaces in an organization, with optional filtering by name search.
167 | 
168 | ### WorkspaceLockRequest
169 | 
170 | **Type:** Request Validation Model
171 | 
172 | **Description:** Used to validate parameters for locking a workspace.
173 | 
174 | **Fields:**
175 | - `workspace_id` (string, required): The ID of the workspace to lock
176 | - `reason` (string, optional): Explanation for locking the workspace
177 | 
178 | **Used by:**
179 | - `lock_workspace` tool function to validate workspace locking parameters
180 | 
181 | ### DataRetentionPolicyRequest
182 | 
183 | **Type:** Request Validation Model
184 | 
185 | **Description:** Parameters for setting a data retention policy on a workspace.
186 | 
187 | **Fields:**
188 | - `workspace_id` (string, required): The ID of the workspace to set the policy for
189 | - `days` (integer, required): Number of days to retain data
190 | 
191 | **JSON representation:**
192 | ```json
193 | {
194 |   "data": {
195 |     "type": "workspace-settings",
196 |     "attributes": {
197 |       "data-retention-days": 30
198 |     }
199 |   }
200 | }
201 | ```
202 | 
203 | **Usage Context:**
204 | Data retention policies control how long Terraform Cloud retains state versions and run history for a workspace, helping manage storage usage and comply with data policies.
205 | 
206 | ## API Response Structure
207 | 
208 | ### Workspace Details Response
209 | 
210 | ```json
211 | {
212 |   "data": {
213 |     "id": "ws-SihZTyXKfNXUWuUa",
214 |     "type": "workspaces",
215 |     "attributes": {
216 |       "name": "my-workspace",
217 |       "description": "Example workspace for terraform configurations",
218 |       "auto-apply": true,
219 |       "created-at": "2023-05-01T12:34:56Z",
220 |       "environment": "default",
221 |       "execution-mode": "remote",
222 |       "file-triggers-enabled": true,
223 |       "global-remote-state": false,
224 |       "locked": false,
225 |       "terraform-version": "1.5.0",
226 |       "trigger-patterns": ["**/*.tf", "*.tfvars"],
227 |       "working-directory": "terraform/"
228 |     },
229 |     "relationships": {
230 |       "organization": {
231 |         "data": {
232 |           "id": "org-ABcd1234",
233 |           "type": "organizations"
234 |         }
235 |       },
236 |       "current-run": {
237 |         "data": null
238 |       },
239 |       "latest-run": {
240 |         "data": {
241 |           "id": "run-CKJhKBXrxZuc9WLS",
242 |           "type": "runs"
243 |         }
244 |       }
245 |     },
246 |     "links": {
247 |       "self": "/api/v2/organizations/my-org/workspaces/my-workspace"
248 |     }
249 |   }
250 | }
251 | ```
252 | 
253 | ### List Workspaces Response
254 | 
255 | ```json
256 | {
257 |   "data": [
258 |     {
259 |       "id": "ws-SihZTyXKfNXUWuUa",
260 |       "type": "workspaces",
261 |       "attributes": {
262 |         "name": "production",
263 |         "description": "Production infrastructure",
264 |         "terraform-version": "1.5.0",
265 |         "created-at": "2023-05-01T12:34:56Z",
266 |         "execution-mode": "remote"
267 |       },
268 |       "relationships": {
269 |         "organization": {
270 |           "data": {
271 |             "id": "org-ABcd1234",
272 |             "type": "organizations"
273 |           }
274 |         },
275 |         "current-state-version": {
276 |           "data": {
277 |             "id": "sv-12345abcde",
278 |             "type": "state-versions"
279 |           }
280 |         }
281 |       }
282 |     },
283 |     {
284 |       "id": "ws-TjqZUyYLfOXWhwbC",
285 |       "type": "workspaces",
286 |       "attributes": {
287 |         "name": "staging",
288 |         "description": "Staging infrastructure",
289 |         "terraform-version": "1.5.0",
290 |         "created-at": "2023-05-02T09:12:34Z",
291 |         "execution-mode": "remote"
292 |       },
293 |       "relationships": {
294 |         "organization": {
295 |           "data": {
296 |             "id": "org-ABcd1234",
297 |             "type": "organizations"
298 |           }
299 |         }
300 |       }
301 |     }
302 |   ],
303 |   "meta": {
304 |     "pagination": {
305 |       "current-page": 1,
306 |       "page-size": 20,
307 |       "prev-page": null,
308 |       "next-page": null,
309 |       "total-pages": 1,
310 |       "total-count": 2
311 |     }
312 |   }
313 | }
314 | ```
315 | 
316 | ## Related Resources
317 | 
318 | - [Workspace Tools](../tools/workspace.md)
319 | - [Organization Models](organization.md)
320 | - [Run Models](run.md)
321 | - [Project Models](project.md)
322 | - [Terraform Cloud API - Workspaces](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces)
```

--------------------------------------------------------------------------------
/terraform_cloud_mcp/models/workspaces.py:
--------------------------------------------------------------------------------

```python
  1 | """Workspace models for Terraform Cloud API
  2 | 
  3 | This module contains models for Terraform Cloud workspace-related requests.
  4 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces
  5 | """
  6 | 
  7 | from typing import Dict, List, Optional, Union
  8 | 
  9 | from pydantic import Field
 10 | 
 11 | from .base import APIRequest, ExecutionMode
 12 | 
 13 | 
 14 | class VcsRepoConfig(APIRequest):
 15 |     """VCS repository configuration for a workspace.
 16 | 
 17 |     Defines version control system repository configuration for a workspace,
 18 |     including branch, repository identifier, OAuth token, and other settings.
 19 | 
 20 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces
 21 | 
 22 |     See:
 23 |         docs/models/workspace.md for reference
 24 |     """
 25 | 
 26 |     # Inherits model_config from APIRequest -> BaseModelConfig
 27 | 
 28 |     branch: Optional[str] = Field(
 29 |         None, description="The repository branch that Terraform executes from"
 30 |     )
 31 |     identifier: Optional[str] = Field(
 32 |         None, description="A reference to your VCS repository in the format :org/:repo"
 33 |     )
 34 |     ingress_submodules: Optional[bool] = Field(
 35 |         None,
 36 |         alias="ingress-submodules",
 37 |         description="Whether submodules should be fetched when cloning the VCS repository",
 38 |     )
 39 |     oauth_token_id: Optional[str] = Field(
 40 |         None,
 41 |         alias="oauth-token-id",
 42 |         description="Specifies the VCS OAuth connection and token",
 43 |     )
 44 |     github_app_installation_id: Optional[str] = Field(
 45 |         None,
 46 |         alias="github-app-installation-id",
 47 |         description="The VCS Connection GitHub App Installation to use",
 48 |     )
 49 |     tags_regex: Optional[str] = Field(
 50 |         None,
 51 |         alias="tags-regex",
 52 |         description="A regular expression used to match Git tags",
 53 |     )
 54 | 
 55 | 
 56 | class WorkspaceListRequest(APIRequest):
 57 |     """Request parameters for listing workspaces in an organization.
 58 | 
 59 |     Defines the parameters for the workspace listing API including pagination
 60 |     and search filtering options.
 61 | 
 62 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces#list-workspaces
 63 | 
 64 |     See:
 65 |         docs/models/workspace.md for reference
 66 |     """
 67 | 
 68 |     organization: str = Field(
 69 |         ...,
 70 |         # No alias needed as field name matches API field name
 71 |         description="The name of the organization to list workspaces from",
 72 |     )
 73 |     page_number: Optional[int] = Field(1, ge=1, description="Page number to fetch")
 74 |     page_size: Optional[int] = Field(
 75 |         20, ge=1, le=100, description="Number of results per page"
 76 |     )
 77 |     search: Optional[str] = Field(None, description="Substring to search for")
 78 | 
 79 | 
 80 | class BaseWorkspaceRequest(APIRequest):
 81 |     """Base class for workspace create and update requests with common fields.
 82 | 
 83 |     This includes common fields used in request payloads for workspace
 84 |     creation and update APIs, providing a foundation for more specific workspace models.
 85 | 
 86 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces
 87 | 
 88 |     Note:
 89 |         This class inherits model_config from APIRequest -> BaseModelConfig and provides
 90 |         default values for most fields based on Terraform Cloud API defaults.
 91 | 
 92 |     See:
 93 |         docs/models/workspace.md for detailed field descriptions and usage examples
 94 |     """
 95 | 
 96 |     # Fields common to both create and update requests with API defaults from docs
 97 |     name: Optional[str] = Field(
 98 |         None,
 99 |         # No alias needed as field name matches API field name
100 |         description="Name of the workspace",
101 |     )
102 |     description: Optional[str] = Field(
103 |         None,
104 |         # No alias needed as field name matches API field name
105 |         description="Description of the workspace",
106 |     )
107 |     execution_mode: Optional[Union[str, ExecutionMode]] = Field(
108 |         ExecutionMode.REMOTE,
109 |         alias="execution-mode",
110 |         description="How operations are executed",
111 |     )
112 |     agent_pool_id: Optional[str] = Field(
113 |         None, alias="agent-pool-id", description="The ID of the agent pool"
114 |     )
115 |     assessments_enabled: Optional[bool] = Field(
116 |         False,
117 |         alias="assessments-enabled",
118 |         description="Whether to perform health assessments",
119 |     )
120 |     auto_apply: Optional[bool] = Field(
121 |         False,
122 |         alias="auto-apply",
123 |         description="Whether to automatically apply changes in runs triggered by VCS, UI, or CLI",
124 |     )
125 |     auto_apply_run_trigger: Optional[bool] = Field(
126 |         False,
127 |         alias="auto-apply-run-trigger",
128 |         description="Whether to automatically apply changes initiated by run triggers",
129 |     )
130 |     auto_destroy_at: Optional[str] = Field(
131 |         None,
132 |         alias="auto-destroy-at",
133 |         description="Timestamp when the next scheduled destroy run will occur",
134 |     )
135 |     auto_destroy_activity_duration: Optional[str] = Field(
136 |         None,
137 |         alias="auto-destroy-activity-duration",
138 |         description="Value and units for automatically scheduled destroy runs based on workspace activity",
139 |     )
140 |     file_triggers_enabled: Optional[bool] = Field(
141 |         True,
142 |         alias="file-triggers-enabled",
143 |         description="Whether to filter runs based on file paths",
144 |     )
145 |     working_directory: Optional[str] = Field(
146 |         None,
147 |         alias="working-directory",
148 |         description="The directory to execute commands in",
149 |     )
150 |     speculative_enabled: Optional[bool] = Field(
151 |         True,
152 |         alias="speculative-enabled",
153 |         description="Whether this workspace allows speculative plans",
154 |     )
155 |     terraform_version: Optional[str] = Field(
156 |         "latest",
157 |         alias="terraform-version",
158 |         description="Specifies the version of Terraform to use for this workspace",
159 |     )
160 |     global_remote_state: Optional[bool] = Field(
161 |         False,
162 |         alias="global-remote-state",
163 |         description="Whether to allow all workspaces to access this workspace's state",
164 |     )
165 |     vcs_repo: Optional[Union[VcsRepoConfig, None]] = Field(
166 |         None,
167 |         alias="vcs-repo",
168 |         description="Settings for the workspace's VCS repository",
169 |     )
170 |     allow_destroy_plan: Optional[bool] = Field(
171 |         True,
172 |         alias="allow-destroy-plan",
173 |         description="Whether to allow destruction plans",
174 |     )
175 |     queue_all_runs: Optional[bool] = Field(
176 |         False,
177 |         alias="queue-all-runs",
178 |         description="Whether runs should be queued immediately",
179 |     )
180 |     source_name: Optional[str] = Field(
181 |         None,
182 |         alias="source-name",
183 |         description="Indicates where the workspace settings originated",
184 |     )
185 |     source_url: Optional[str] = Field(
186 |         None, alias="source-url", description="URL to origin source"
187 |     )
188 |     trigger_prefixes: Optional[List[str]] = Field(
189 |         None, alias="trigger-prefixes", description="List of paths that trigger runs"
190 |     )
191 |     trigger_patterns: Optional[List[str]] = Field(
192 |         None,
193 |         alias="trigger-patterns",
194 |         description="List of glob patterns that trigger runs",
195 |     )
196 |     setting_overwrites: Optional[Dict[str, bool]] = Field(
197 |         None,
198 |         alias="setting-overwrites",
199 |         description="Specifies attributes that have organization-level defaults",
200 |     )
201 | 
202 | 
203 | class WorkspaceCreateRequest(BaseWorkspaceRequest):
204 |     """Request model for creating a Terraform Cloud workspace.
205 | 
206 |     Validates and structures the request according to the Terraform Cloud API
207 |     requirements for creating workspaces. Extends BaseWorkspaceRequest with
208 |     required fields for creation.
209 | 
210 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces#create-a-workspace
211 | 
212 |     Note:
213 |         This inherits all configuration fields from BaseWorkspaceRequest
214 |         while making organization and name required.
215 | 
216 |     See:
217 |         docs/models/workspace.md for reference
218 |     """
219 | 
220 |     # Override organization and name to make them required for creation
221 |     organization: str = Field(
222 |         ...,
223 |         # No alias needed as field name matches API field name
224 |         description="The name of the organization to create the workspace in",
225 |     )
226 |     name: str = Field(
227 |         ...,
228 |         # No alias needed as field name matches API field name
229 |         description="Name of the workspace",
230 |     )
231 | 
232 | 
233 | class WorkspaceUpdateRequest(BaseWorkspaceRequest):
234 |     """Request model for updating a Terraform Cloud workspace.
235 | 
236 |     Validates and structures the request for updating workspaces. Extends BaseWorkspaceRequest
237 |     with routing fields while keeping all configuration fields optional.
238 | 
239 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces#update-a-workspace
240 | 
241 |     Note:
242 |         This inherits all configuration fields from BaseWorkspaceRequest
243 |         and adds required routing fields for the update operation.
244 | 
245 |     See:
246 |         docs/models/workspace.md for reference
247 |     """
248 | 
249 |     # Add fields which are required for updates but not part of the workspace attributes payload
250 |     organization: str = Field(
251 |         ...,
252 |         # No alias needed as field name matches API field name
253 |         description="The name of the organization that owns the workspace",
254 |     )
255 |     workspace_name: str = Field(
256 |         ...,
257 |         # No alias needed as field name matches API field name
258 |         description="The name of the workspace to update",
259 |     )
260 | 
261 | 
262 | class WorkspaceParams(BaseWorkspaceRequest):
263 |     """Parameters for workspace operations without routing fields.
264 | 
265 |     This model provides all optional parameters for creating or updating workspaces,
266 |     reusing field definitions from BaseWorkspaceRequest. It separates configuration
267 |     parameters from routing information like organization and workspace name.
268 | 
269 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces
270 | 
271 |     Note:
272 |         When updating a workspace, use this model to specify only the attributes
273 |         you want to change. Unspecified attributes retain their current values.
274 |         All fields are inherited from BaseWorkspaceRequest.
275 | 
276 |     See:
277 |         docs/models/workspace.md for reference
278 |     """
279 | 
280 |     # Inherits model_config and all fields from BaseWorkspaceRequest
281 | 
282 | 
283 | # Response handling is implemented through raw dictionaries
284 | 
285 | 
286 | class DataRetentionPolicyRequest(APIRequest):
287 |     """Request model for setting a data retention policy.
288 | 
289 |     Defines the parameters for the data retention policy API to specify
290 |     how long Terraform Cloud should keep run history and state files.
291 | 
292 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces#create-a-data-retention-policy
293 | 
294 |     See:
295 |         docs/models/workspace.md for reference
296 |     """
297 | 
298 |     workspace_id: str = Field(
299 |         ..., description="The ID of the workspace to set the policy for"
300 |     )
301 |     days: int = Field(..., description="Number of days to retain data")
302 | 
```

--------------------------------------------------------------------------------
/docs/models/variables.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Variables Models
  2 | 
  3 | This document describes the data models used for variable and variable set operations in Terraform Cloud.
  4 | 
  5 | ## Overview
  6 | 
  7 | Variable models provide structure and validation for interacting with the Terraform Cloud Variables API. These models define workspace variable configuration, variable set management, and cross-workspace variable sharing. Variables serve as input parameters for Terraform configurations and environment settings for runs, while variable sets enable reusable variable collections across multiple workspaces and projects.
  8 | 
  9 | ## Models Reference
 10 | 
 11 | ### VariableCategory
 12 | 
 13 | **Type:** Enum (string)
 14 | 
 15 | **Description:** Defines the type of variable for use in Terraform operations.
 16 | 
 17 | **Values:**
 18 | - `terraform`: Terraform input variables available in configuration
 19 | - `env`: Environment variables available during plan/apply operations
 20 | 
 21 | **JSON representation:**
 22 | ```json
 23 | {
 24 |   "category": "terraform"
 25 | }
 26 | ```
 27 | 
 28 | **Usage Context:**
 29 | The variable category determines how the variable is exposed during Terraform operations. Terraform variables are available as input variables in the configuration, while environment variables are available to the Terraform process and any custom scripts.
 30 | 
 31 | **Notes:**
 32 | - HCL format is only valid for terraform category variables
 33 | - Environment variables are typically used for provider authentication or configuration
 34 | 
 35 | ### WorkspaceVariable
 36 | 
 37 | **Type:** Object
 38 | 
 39 | **Description:** Complete model for workspace variable data including all configuration options.
 40 | 
 41 | **Fields:**
 42 | - `key` (string, required): Variable name/key (1-255 characters)
 43 | - `value` (string, optional): Variable value (max 256,000 characters)
 44 | - `description` (string, optional): Description of the variable (max 512 characters)
 45 | - `category` (VariableCategory, required): Variable category (terraform or env)
 46 | - `hcl` (boolean, optional): Whether the value is HCL code (default: false, terraform only)
 47 | - `sensitive` (boolean, optional): Whether the variable value is sensitive (default: false)
 48 | 
 49 | **JSON representation:**
 50 | ```json
 51 | {
 52 |   "data": {
 53 |     "type": "vars",
 54 |     "attributes": {
 55 |       "key": "instance_type",
 56 |       "value": "t3.micro",
 57 |       "description": "EC2 instance type for the web server",
 58 |       "category": "terraform",
 59 |       "hcl": false,
 60 |       "sensitive": false
 61 |     }
 62 |   }
 63 | }
 64 | ```
 65 | 
 66 | **Usage Context:**
 67 | Workspace variables provide configuration values specific to a single workspace. They can be Terraform input variables or environment variables, with support for sensitive values and HCL syntax for complex data structures.
 68 | 
 69 | ### VariableSet
 70 | 
 71 | **Type:** Object
 72 | 
 73 | **Description:** Configuration model for variable sets that can be shared across workspaces and projects.
 74 | 
 75 | **Fields:**
 76 | - `name` (string, required): Variable set name (1-90 characters)
 77 | - `description` (string, optional): Description of the variable set (max 512 characters)
 78 | - `global` (boolean, optional): Whether this is a global variable set (default: false)
 79 | - `priority` (boolean, optional): Whether this variable set takes priority over workspace variables (default: false)
 80 | 
 81 | **JSON representation:**
 82 | ```json
 83 | {
 84 |   "data": {
 85 |     "type": "varsets",
 86 |     "attributes": {
 87 |       "name": "production-env",
 88 |       "description": "Common variables for production environment",
 89 |       "global": false,
 90 |       "priority": true
 91 |     }
 92 |   }
 93 | }
 94 | ```
 95 | 
 96 | **Usage Context:**
 97 | Variable sets enable sharing common variables across multiple workspaces and projects. Global variable sets are automatically applied to all workspaces, while priority variable sets override workspace-level variables with the same keys.
 98 | 
 99 | ### WorkspaceVariableParams
100 | 
101 | **Type:** Object
102 | 
103 | **Description:** Parameters for workspace variable operations without routing fields. Used to specify configuration parameters for creating or updating workspace variables.
104 | 
105 | **Fields:**
106 | - `key` (string, optional): Variable name/key
107 | - `value` (string, optional): Variable value
108 | - `description` (string, optional): Description of the variable
109 | - `category` (VariableCategory, optional): Variable category (terraform or env)
110 | - `hcl` (boolean, optional): Whether the value is HCL code (terraform variables only)
111 | - `sensitive` (boolean, optional): Whether the variable value is sensitive
112 | 
113 | **Usage Context:**
114 | Used as optional parameters in variable creation and update operations, allowing specification of only the fields that need to be set or changed.
115 | 
116 | ### VariableSetParams
117 | 
118 | **Type:** Object
119 | 
120 | **Description:** Parameters for variable set operations without routing fields. Used to specify configuration parameters for creating or updating variable sets.
121 | 
122 | **Fields:**
123 | - `name` (string, optional): Variable set name
124 | - `description` (string, optional): Description of the variable set
125 | - `global` (boolean, optional): Whether this is a global variable set
126 | - `priority` (boolean, optional): Whether this variable set takes priority over workspace variables
127 | 
128 | **Usage Context:**
129 | Used as optional parameters in variable set creation and update operations, enabling modification of only specified attributes while leaving others unchanged.
130 | 
131 | ### WorkspaceVariableCreateRequest
132 | 
133 | **Type:** Request Validation Model
134 | 
135 | **Description:** Used to validate parameters for creating workspace variables.
136 | 
137 | **Fields:**
138 | - `workspace_id` (string, required): The workspace ID (format: "ws-xxxxxxxx")
139 | - `key` (string, required): Variable name/key
140 | - `category` (VariableCategory, required): Variable category
141 | - `params` (WorkspaceVariableParams, optional): Additional variable parameters
142 | 
143 | **Used by:**
144 | - `create_workspace_variable` tool function to validate variable creation parameters
145 | 
146 | ### WorkspaceVariableUpdateRequest
147 | 
148 | **Type:** Request Validation Model
149 | 
150 | **Description:** Used to validate parameters for updating workspace variables.
151 | 
152 | **Fields:**
153 | - `workspace_id` (string, required): The workspace ID (format: "ws-xxxxxxxx")
154 | - `variable_id` (string, required): The variable ID (format: "var-xxxxxxxx")
155 | - `params` (WorkspaceVariableParams, optional): Variable parameters to update
156 | 
157 | **Used by:**
158 | - `update_workspace_variable` tool function to validate variable update parameters
159 | 
160 | ### VariableSetCreateRequest
161 | 
162 | **Type:** Request Validation Model
163 | 
164 | **Description:** Used to validate parameters for creating variable sets.
165 | 
166 | **Fields:**
167 | - `organization` (string, required): The organization name
168 | - `name` (string, required): Variable set name
169 | - `params` (VariableSetParams, optional): Additional variable set parameters
170 | 
171 | **Used by:**
172 | - `create_variable_set` tool function to validate variable set creation parameters
173 | 
174 | ### VariableSetUpdateRequest
175 | 
176 | **Type:** Request Validation Model
177 | 
178 | **Description:** Used to validate parameters for updating variable sets.
179 | 
180 | **Fields:**
181 | - `varset_id` (string, required): The variable set ID (format: "varset-xxxxxxxx")
182 | - `params` (VariableSetParams, optional): Variable set parameters to update
183 | 
184 | **Used by:**
185 | - `update_variable_set` tool function to validate variable set update parameters
186 | 
187 | ### VariableSetAssignmentRequest
188 | 
189 | **Type:** Request Validation Model
190 | 
191 | **Description:** Used to validate parameters for assigning variable sets to workspaces or projects.
192 | 
193 | **Fields:**
194 | - `varset_id` (string, required): The variable set ID (format: "varset-xxxxxxxx")
195 | - `workspace_ids` (List[str], optional): List of workspace IDs to assign
196 | - `project_ids` (List[str], optional): List of project IDs to assign
197 | 
198 | **Used by:**
199 | - `assign_variable_set_to_workspaces` and `assign_variable_set_to_projects` tool functions
200 | 
201 | ## API Response Structure
202 | 
203 | ### Workspace Variable Response
204 | 
205 | ```json
206 | {
207 |   "data": {
208 |     "id": "var-EavQ1LztoRTQHSNT",
209 |     "type": "vars",
210 |     "attributes": {
211 |       "key": "image_id",
212 |       "value": "ami-0c55b159cbfafe1d0",
213 |       "description": "AMI ID for the EC2 instance",
214 |       "category": "terraform",
215 |       "hcl": false,
216 |       "sensitive": false,
217 |       "created-at": "2023-05-01T12:34:56Z",
218 |       "updated-at": "2023-05-01T12:34:56Z"
219 |     },
220 |     "relationships": {
221 |       "configurable": {
222 |         "data": {
223 |           "id": "ws-SihZTyXKfNXUWuUa",
224 |           "type": "workspaces"
225 |         }
226 |       }
227 |     }
228 |   }
229 | }
230 | ```
231 | 
232 | ### List Workspace Variables Response
233 | 
234 | ```json
235 | {
236 |   "data": [
237 |     {
238 |       "id": "var-EavQ1LztoRTQHSNT",
239 |       "type": "vars",
240 |       "attributes": {
241 |         "key": "image_id",
242 |         "value": "ami-0c55b159cbfafe1d0",
243 |         "description": "AMI ID for the EC2 instance",
244 |         "category": "terraform",
245 |         "hcl": false,
246 |         "sensitive": false
247 |       }
248 |     },
249 |     {
250 |       "id": "var-GjyK2MzupSTRJTOU",
251 |       "type": "vars",
252 |       "attributes": {
253 |         "key": "DATABASE_URL",
254 |         "value": null,
255 |         "description": "Database connection string",
256 |         "category": "env",
257 |         "hcl": false,
258 |         "sensitive": true
259 |       }
260 |     }
261 |   ]
262 | }
263 | ```
264 | 
265 | ### Variable Set Response
266 | 
267 | ```json
268 | {
269 |   "data": {
270 |     "id": "varset-47qC5ydmtMa8cYs2",
271 |     "type": "varsets",
272 |     "attributes": {
273 |       "name": "aws-common-config",
274 |       "description": "Common AWS configuration variables",
275 |       "global": false,
276 |       "priority": true,
277 |       "created-at": "2023-05-01T12:34:56Z",
278 |       "updated-at": "2023-05-01T12:34:56Z"
279 |     },
280 |     "relationships": {
281 |       "organization": {
282 |         "data": {
283 |           "id": "org-ABcd1234",
284 |           "type": "organizations"
285 |         }
286 |       },
287 |       "vars": {
288 |         "data": [
289 |           {
290 |             "id": "var-EavQ1LztoRTQHSNT",
291 |             "type": "vars"
292 |           }
293 |         ]
294 |       },
295 |       "workspaces": {
296 |         "data": [
297 |           {
298 |             "id": "ws-SihZTyXKfNXUWuUa",
299 |             "type": "workspaces"
300 |           }
301 |         ]
302 |       }
303 |     }
304 |   }
305 | }
306 | ```
307 | 
308 | ### List Variable Sets Response
309 | 
310 | ```json
311 | {
312 |   "data": [
313 |     {
314 |       "id": "varset-47qC5ydmtMa8cYs2",
315 |       "type": "varsets",
316 |       "attributes": {
317 |         "name": "production-config",
318 |         "description": "Production environment variables",
319 |         "global": false,
320 |         "priority": true,
321 |         "created-at": "2023-05-01T12:34:56Z"
322 |       },
323 |       "relationships": {
324 |         "organization": {
325 |           "data": {
326 |             "id": "org-ABcd1234",
327 |             "type": "organizations"
328 |           }
329 |         }
330 |       }
331 |     },
332 |     {
333 |       "id": "varset-58rD6zemvNb9dZt3",
334 |       "type": "varsets",
335 |       "attributes": {
336 |         "name": "global-config",
337 |         "description": "Global configuration variables",
338 |         "global": true,
339 |         "priority": false,
340 |         "created-at": "2023-05-02T09:12:34Z"
341 |       }
342 |     }
343 |   ],
344 |   "meta": {
345 |     "pagination": {
346 |       "current-page": 1,
347 |       "page-size": 20,
348 |       "prev-page": null,
349 |       "next-page": null,
350 |       "total-pages": 1,
351 |       "total-count": 2
352 |     }
353 |   }
354 | }
355 | ```
356 | 
357 | ## Related Resources
358 | 
359 | - [Variable Tools](../tools/variables.md)
360 | - [Workspace Models](workspace.md)
361 | - [Project Models](project.md)
362 | - [Terraform Cloud API - Workspace Variables](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-variables)
363 | - [Terraform Cloud API - Variable Sets](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets)
```

--------------------------------------------------------------------------------
/terraform_cloud_mcp/tools/projects.py:
--------------------------------------------------------------------------------

```python
  1 | """Project management tools for Terraform Cloud MCP
  2 | 
  3 | This module implements the project-related endpoints of the Terraform Cloud API.
  4 | Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/projects
  5 | """
  6 | 
  7 | import logging
  8 | from typing import Dict, List, Optional
  9 | 
 10 | from ..api.client import api_request
 11 | from ..utils.decorators import handle_api_errors
 12 | from ..utils.payload import create_api_payload
 13 | from ..utils.request import query_params
 14 | from ..models.base import APIResponse
 15 | from ..models.projects import (
 16 |     ProjectCreateRequest,
 17 |     ProjectUpdateRequest,
 18 |     ProjectListRequest,
 19 |     ProjectParams,
 20 |     ProjectTagBindingRequest,
 21 |     TagBinding,
 22 |     WorkspaceMoveRequest,
 23 | )
 24 | 
 25 | 
 26 | @handle_api_errors
 27 | async def create_project(
 28 |     organization: str, name: str, params: Optional[ProjectParams] = None
 29 | ) -> APIResponse:
 30 |     """Create a new project in an organization.
 31 | 
 32 |     Creates a new Terraform Cloud project which serves as a container for workspaces.
 33 |     Projects help organize workspaces into logical groups and can have their own
 34 |     settings and permissions.
 35 | 
 36 |     API endpoint: POST /organizations/{organization}/projects
 37 | 
 38 |     Args:
 39 |         organization: The name of the organization
 40 |         name: The name to give the project
 41 |         params: Additional project parameters (optional):
 42 |             - description: Human-readable description of the project
 43 |             - auto_destroy_activity_duration: How long each workspace should wait before auto-destroying
 44 |               (e.g., '14d', '24h')
 45 |             - tag_bindings: List of tag key-value pairs to bind to the project
 46 | 
 47 |     Returns:
 48 |         The created project data including configuration, settings and metadata
 49 | 
 50 |     See:
 51 |         docs/tools/project.md for reference documentation
 52 |     """
 53 |     param_dict = params.model_dump(exclude_none=True) if params else {}
 54 |     request = ProjectCreateRequest(organization=organization, name=name, **param_dict)
 55 | 
 56 |     # Create the base payload
 57 |     payload = create_api_payload(
 58 |         resource_type="projects", model=request, exclude_fields={"organization"}
 59 |     )
 60 | 
 61 |     # Handle tag bindings if present
 62 |     if request.tag_bindings:
 63 |         tag_bindings_data = []
 64 |         for tag in request.tag_bindings:
 65 |             tag_bindings_data.append(
 66 |                 {
 67 |                     "type": "tag-bindings",
 68 |                     "attributes": {"key": tag.key, "value": tag.value},
 69 |                 }
 70 |             )
 71 | 
 72 |         if "relationships" not in payload["data"]:
 73 |             payload["data"]["relationships"] = {}
 74 | 
 75 |         payload["data"]["relationships"]["tag-bindings"] = {"data": tag_bindings_data}
 76 | 
 77 |     # Remove tag-bindings from attributes if present since we've moved them to relationships
 78 |     if "tag-bindings" in payload["data"]["attributes"]:
 79 |         del payload["data"]["attributes"]["tag-bindings"]
 80 | 
 81 |     logger = logging.getLogger(__name__)
 82 |     logger.debug(f"Create project payload: {payload}")
 83 | 
 84 |     return await api_request(
 85 |         f"organizations/{organization}/projects", method="POST", data=payload
 86 |     )
 87 | 
 88 | 
 89 | @handle_api_errors
 90 | async def update_project(
 91 |     project_id: str, params: Optional[ProjectParams] = None
 92 | ) -> APIResponse:
 93 |     """Update an existing project.
 94 | 
 95 |     Modifies the settings of a Terraform Cloud project. This can be used to change
 96 |     attributes like name, description, auto-destroy duration, or tags. Only specified
 97 |     attributes will be updated; unspecified attributes remain unchanged.
 98 | 
 99 |     API endpoint: PATCH /projects/{project_id}
100 | 
101 |     Args:
102 |         project_id: The ID of the project to update (format: "prj-xxxxxxxx")
103 |         params: Project parameters to update (optional):
104 |             - name: New name for the project
105 |             - description: Human-readable description of the project
106 |             - auto_destroy_activity_duration: How long each workspace should wait before
107 |               auto-destroying (e.g., '14d', '24h')
108 |             - tag_bindings: List of tag key-value pairs to bind to the project
109 | 
110 |     Returns:
111 |         The updated project with all current settings and configuration
112 | 
113 |     See:
114 |         docs/tools/project.md for reference documentation
115 |     """
116 |     # Extract parameters from the params object if provided
117 |     param_dict = params.model_dump(exclude_none=True) if params else {}
118 | 
119 |     # Create request using Pydantic model
120 |     request = ProjectUpdateRequest(project_id=project_id, **param_dict)
121 | 
122 |     # Create base API payload using utility function
123 |     payload = create_api_payload(
124 |         resource_type="projects",
125 |         model=request,
126 |         exclude_fields={"project_id"},
127 |     )
128 | 
129 |     # Handle tag bindings if present
130 |     if request.tag_bindings:
131 |         tag_bindings_data = []
132 |         for tag in request.tag_bindings:
133 |             tag_bindings_data.append(
134 |                 {
135 |                     "type": "tag-bindings",
136 |                     "attributes": {"key": tag.key, "value": tag.value},
137 |                 }
138 |             )
139 | 
140 |         if "relationships" not in payload["data"]:
141 |             payload["data"]["relationships"] = {}
142 | 
143 |         payload["data"]["relationships"]["tag-bindings"] = {"data": tag_bindings_data}
144 | 
145 |     # Remove tag-bindings from attributes if present since we've moved them to relationships
146 |     if "tag-bindings" in payload["data"]["attributes"]:
147 |         del payload["data"]["attributes"]["tag-bindings"]
148 | 
149 |     # Log payload for debugging
150 |     logger = logging.getLogger(__name__)
151 |     logger.debug(f"Update project payload: {payload}")
152 | 
153 |     # Make API request
154 |     return await api_request(f"projects/{project_id}", method="PATCH", data=payload)
155 | 
156 | 
157 | @handle_api_errors
158 | async def list_projects(
159 |     organization: str,
160 |     page_number: int = 1,
161 |     page_size: int = 20,
162 |     q: Optional[str] = None,
163 |     filter_names: Optional[str] = None,
164 |     filter_permissions_update: Optional[bool] = None,
165 |     filter_permissions_create_workspace: Optional[bool] = None,
166 |     sort: Optional[str] = None,
167 | ) -> APIResponse:
168 |     """List projects in an organization.
169 | 
170 |     Retrieves a paginated list of all projects in a Terraform Cloud organization.
171 |     Results can be filtered using a search string or permissions filters to find
172 |     specific projects.
173 | 
174 |     API endpoint: GET /organizations/{organization}/projects
175 | 
176 |     Args:
177 |         organization: The name of the organization to list projects from
178 |         page_number: The page number to return (default: 1)
179 |         page_size: The number of items per page (default: 20, max: 100)
180 |         q: Optional search query to filter projects by name
181 |         filter_names: Filter projects by name (comma-separated list)
182 |         filter_permissions_update: Filter projects that the user can update
183 |         filter_permissions_create_workspace: Filter projects that the user can create workspaces in
184 |         sort: Sort projects by name ('name' or '-name' for descending)
185 | 
186 |     Returns:
187 |         Paginated list of projects with their configuration settings and metadata
188 | 
189 |     See:
190 |         docs/tools/project.md for reference documentation
191 |     """
192 |     # Create request using Pydantic model for validation
193 |     request = ProjectListRequest(
194 |         organization=organization,
195 |         page_number=page_number,
196 |         page_size=page_size,
197 |         q=q,
198 |         filter_names=filter_names,
199 |         filter_permissions_update=filter_permissions_update,
200 |         filter_permissions_create_workspace=filter_permissions_create_workspace,
201 |         sort=sort,
202 |     )
203 | 
204 |     # Use the unified query params utility function
205 |     params = query_params(request)
206 | 
207 |     # Make API request
208 |     return await api_request(
209 |         f"organizations/{organization}/projects", method="GET", params=params
210 |     )
211 | 
212 | 
213 | @handle_api_errors
214 | async def get_project_details(project_id: str) -> APIResponse:
215 |     """Get details for a specific project.
216 | 
217 |     Retrieves comprehensive information about a project including its configuration,
218 |     tag bindings, workspace count, and other attributes.
219 | 
220 |     API endpoint: GET /projects/{project_id}
221 | 
222 |     Args:
223 |         project_id: The ID of the project (format: "prj-xxxxxxxx")
224 | 
225 |     Returns:
226 |         Project details including settings, configuration and status
227 | 
228 |     See:
229 |         docs/tools/project.md for reference documentation
230 |     """
231 |     # Make API request
232 |     return await api_request(f"projects/{project_id}", method="GET")
233 | 
234 | 
235 | @handle_api_errors
236 | async def delete_project(project_id: str) -> APIResponse:
237 |     """Delete a project.
238 | 
239 |     Permanently deletes a Terraform Cloud project. This operation will
240 |     fail if the project contains any workspaces or stacks.
241 | 
242 |     API endpoint: DELETE /projects/{project_id}
243 | 
244 |     Args:
245 |         project_id: The ID of the project to delete (format: "prj-xxxxxxxx")
246 | 
247 |     Returns:
248 |         Empty response with HTTP 204 status code if successful
249 | 
250 |     See:
251 |         docs/tools/project.md for reference documentation
252 |     """
253 |     # Make API request
254 |     return await api_request(f"projects/{project_id}", method="DELETE")
255 | 
256 | 
257 | @handle_api_errors
258 | async def list_project_tag_bindings(project_id: str) -> APIResponse:
259 |     """List tag bindings for a project.
260 | 
261 |     Retrieves the list of tags bound to a specific project. These tags are
262 |     inherited by all workspaces within the project.
263 | 
264 |     API endpoint: GET /projects/{project_id}/tag-bindings
265 | 
266 |     Args:
267 |         project_id: The ID of the project (format: "prj-xxxxxxxx")
268 | 
269 |     Returns:
270 |         List of tag bindings with their key-value pairs and creation timestamps
271 | 
272 |     See:
273 |         docs/tools/project.md for reference documentation
274 |     """
275 |     # Make API request
276 |     return await api_request(f"projects/{project_id}/tag-bindings", method="GET")
277 | 
278 | 
279 | @handle_api_errors
280 | async def add_update_project_tag_bindings(
281 |     project_id: str, tag_bindings: List[TagBinding]
282 | ) -> APIResponse:
283 |     """Add or update tag bindings on a project.
284 | 
285 |     Adds new tag bindings or updates existing ones on a project. This is an
286 |     additive operation that doesn't remove existing tags.
287 | 
288 |     API endpoint: PATCH /projects/{project_id}/tag-bindings
289 | 
290 |     Args:
291 |         project_id: The ID of the project (format: "prj-xxxxxxxx")
292 |         tag_bindings: List of TagBinding objects with key-value pairs to add or update
293 | 
294 |     Returns:
295 |         The complete list of updated tag bindings for the project
296 | 
297 |     See:
298 |         docs/tools/project.md for reference documentation
299 |     """
300 |     # Create request using Pydantic model
301 |     request = ProjectTagBindingRequest(project_id=project_id, tag_bindings=tag_bindings)
302 | 
303 |     # Create payload
304 |     tag_bindings_data = []
305 |     for tag in request.tag_bindings:
306 |         tag_bindings_data.append(
307 |             {"type": "tag-bindings", "attributes": {"key": tag.key, "value": tag.value}}
308 |         )
309 | 
310 |     payload = {"data": tag_bindings_data}
311 | 
312 |     # Make API request
313 |     return await api_request(
314 |         f"projects/{project_id}/tag-bindings", method="PATCH", data=payload
315 |     )
316 | 
317 | 
318 | @handle_api_errors
319 | async def move_workspaces_to_project(
320 |     project_id: str, workspace_ids: List[str]
321 | ) -> APIResponse:
322 |     """Move workspaces into a project.
323 | 
324 |     Moves one or more workspaces into a project. The user must have permission
325 |     to move workspaces on both source and destination projects.
326 | 
327 |     API endpoint: POST /projects/{project_id}/relationships/workspaces
328 | 
329 |     Args:
330 |         project_id: The ID of the destination project (format: "prj-xxxxxxxx")
331 |         workspace_ids: List of workspace IDs to move (format: ["ws-xxxxxxxx", ...])
332 | 
333 |     Returns:
334 |         Empty response with HTTP 204 status code if successful
335 | 
336 |     See:
337 |         docs/tools/project.md for reference documentation
338 |     """
339 |     # Create request using Pydantic model
340 |     request = WorkspaceMoveRequest(project_id=project_id, workspace_ids=workspace_ids)
341 | 
342 |     # Create payload
343 |     payload: Dict[str, List[Dict[str, str]]] = {"data": []}
344 |     for workspace_id in request.workspace_ids:
345 |         payload["data"].append({"type": "workspaces", "id": workspace_id})
346 | 
347 |     # Make API request
348 |     return await api_request(
349 |         f"projects/{project_id}/relationships/workspaces", method="POST", data=payload
350 |     )
351 | 
```

--------------------------------------------------------------------------------
/terraform_cloud_mcp/models/variables.py:
--------------------------------------------------------------------------------

```python
  1 | """Variable models for Terraform Cloud API
  2 | 
  3 | This module contains models for Terraform Cloud variable-related requests,
  4 | including workspace variables and variable sets.
  5 | 
  6 | Reference:
  7 | - https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-variables
  8 | - https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets
  9 | """
 10 | 
 11 | from enum import Enum
 12 | from typing import List, Optional
 13 | 
 14 | from pydantic import Field
 15 | 
 16 | from .base import APIRequest
 17 | 
 18 | 
 19 | class VariableCategory(str, Enum):
 20 |     """Variable category options for workspace variables.
 21 | 
 22 |     Defines the type of variable:
 23 |     - TERRAFORM: Terraform input variables available in configuration
 24 |     - ENV: Environment variables available during plan/apply operations
 25 | 
 26 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-variables
 27 | 
 28 |     See:
 29 |         docs/models/variables.md for reference
 30 |     """
 31 | 
 32 |     TERRAFORM = "terraform"
 33 |     ENV = "env"
 34 | 
 35 | 
 36 | class WorkspaceVariable(APIRequest):
 37 |     """Model for workspace variable data.
 38 | 
 39 |     Represents a variable that can be set on a workspace, including
 40 |     Terraform input variables and environment variables.
 41 | 
 42 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-variables
 43 | 
 44 |     See:
 45 |         docs/models/variables.md for reference
 46 |     """
 47 | 
 48 |     key: str = Field(
 49 |         ...,
 50 |         description="Variable name/key",
 51 |         min_length=1,
 52 |         max_length=255,
 53 |     )
 54 |     value: Optional[str] = Field(
 55 |         None,
 56 |         description="Variable value",
 57 |         max_length=256000,
 58 |     )
 59 |     description: Optional[str] = Field(
 60 |         None,
 61 |         description="Description of the variable",
 62 |         max_length=512,
 63 |     )
 64 |     category: VariableCategory = Field(
 65 |         ...,
 66 |         description="Variable category (terraform or env)",
 67 |     )
 68 |     hcl: Optional[bool] = Field(
 69 |         False,
 70 |         description="Whether the value is HCL code (only valid for terraform variables)",
 71 |     )
 72 |     sensitive: Optional[bool] = Field(
 73 |         False,
 74 |         description="Whether the variable value is sensitive",
 75 |     )
 76 | 
 77 | 
 78 | class WorkspaceVariableParams(APIRequest):
 79 |     """Parameters for workspace variable operations without routing fields.
 80 | 
 81 |     This model provides all optional parameters for creating or updating workspace
 82 |     variables, separating configuration parameters from routing information like
 83 |     workspace ID and variable ID.
 84 | 
 85 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-variables
 86 | 
 87 |     See:
 88 |         docs/models/variables.md for reference
 89 |     """
 90 | 
 91 |     key: Optional[str] = Field(
 92 |         None,
 93 |         description="Variable name/key",
 94 |         min_length=1,
 95 |         max_length=255,
 96 |     )
 97 |     value: Optional[str] = Field(
 98 |         None,
 99 |         description="Variable value",
100 |         max_length=256000,
101 |     )
102 |     description: Optional[str] = Field(
103 |         None,
104 |         description="Description of the variable",
105 |         max_length=512,
106 |     )
107 |     category: Optional[VariableCategory] = Field(
108 |         None,
109 |         description="Variable category (terraform or env)",
110 |     )
111 |     hcl: Optional[bool] = Field(
112 |         None,
113 |         description="Whether the value is HCL code (only valid for terraform variables)",
114 |     )
115 |     sensitive: Optional[bool] = Field(
116 |         None,
117 |         description="Whether the variable value is sensitive",
118 |     )
119 | 
120 | 
121 | class WorkspaceVariableCreateRequest(APIRequest):
122 |     """Request model for creating workspace variables.
123 | 
124 |     Used for POST /workspaces/:workspace_id/vars endpoint.
125 | 
126 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-variables
127 | 
128 |     See:
129 |         docs/models/variables.md for reference
130 |     """
131 | 
132 |     workspace_id: str = Field(
133 |         ...,
134 |         description="The workspace ID",
135 |         pattern=r"^ws-[a-zA-Z0-9]{16}$",
136 |     )
137 |     key: str = Field(
138 |         ...,
139 |         description="Variable name/key",
140 |         min_length=1,
141 |         max_length=255,
142 |     )
143 |     category: VariableCategory = Field(
144 |         ...,
145 |         description="Variable category (terraform or env)",
146 |     )
147 |     value: Optional[str] = Field(
148 |         None,
149 |         description="Variable value",
150 |         max_length=256000,
151 |     )
152 |     description: Optional[str] = Field(
153 |         None,
154 |         description="Description of the variable",
155 |         max_length=512,
156 |     )
157 |     hcl: Optional[bool] = Field(
158 |         None,
159 |         description="Whether the value is HCL code (only valid for terraform variables)",
160 |     )
161 |     sensitive: Optional[bool] = Field(
162 |         None,
163 |         description="Whether the variable value is sensitive",
164 |     )
165 | 
166 | 
167 | class WorkspaceVariableUpdateRequest(APIRequest):
168 |     """Request model for updating workspace variables.
169 | 
170 |     Used for PATCH /workspaces/:workspace_id/vars/:variable_id endpoint.
171 | 
172 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-variables
173 | 
174 |     See:
175 |         docs/models/variables.md for reference
176 |     """
177 | 
178 |     workspace_id: str = Field(
179 |         ...,
180 |         description="The workspace ID",
181 |         pattern=r"^ws-[a-zA-Z0-9]{16}$",
182 |     )
183 |     variable_id: str = Field(
184 |         ...,
185 |         description="The variable ID",
186 |         pattern=r"^var-[a-zA-Z0-9]{16}$",
187 |     )
188 |     key: Optional[str] = Field(
189 |         None,
190 |         description="Variable name/key",
191 |         min_length=1,
192 |         max_length=255,
193 |     )
194 |     value: Optional[str] = Field(
195 |         None,
196 |         description="Variable value",
197 |         max_length=256000,
198 |     )
199 |     description: Optional[str] = Field(
200 |         None,
201 |         description="Description of the variable",
202 |         max_length=512,
203 |     )
204 |     category: Optional[VariableCategory] = Field(
205 |         None,
206 |         description="Variable category (terraform or env)",
207 |     )
208 |     hcl: Optional[bool] = Field(
209 |         None,
210 |         description="Whether the value is HCL code (only valid for terraform variables)",
211 |     )
212 |     sensitive: Optional[bool] = Field(
213 |         None,
214 |         description="Whether the variable value is sensitive",
215 |     )
216 | 
217 | 
218 | # Variable Sets Models
219 | 
220 | 
221 | class VariableSet(APIRequest):
222 |     """Model for variable set data.
223 | 
224 |     Represents a collection of variables that can be applied to multiple
225 |     workspaces or projects.
226 | 
227 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets
228 | 
229 |     See:
230 |         docs/models/variables.md for reference
231 |     """
232 | 
233 |     name: str = Field(
234 |         ...,
235 |         description="Variable set name",
236 |         min_length=1,
237 |         max_length=90,
238 |     )
239 |     description: Optional[str] = Field(
240 |         None,
241 |         description="Description of the variable set",
242 |         max_length=512,
243 |     )
244 |     global_: Optional[bool] = Field(
245 |         False,
246 |         alias="global",
247 |         description="Whether this is a global variable set",
248 |     )
249 |     priority: Optional[bool] = Field(
250 |         False,
251 |         description="Whether this variable set takes priority over workspace variables",
252 |     )
253 | 
254 | 
255 | class VariableSetParams(APIRequest):
256 |     """Parameters for variable set operations without routing fields.
257 | 
258 |     This model provides all optional parameters for creating or updating variable
259 |     sets, separating configuration parameters from routing information.
260 | 
261 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets
262 | 
263 |     See:
264 |         docs/models/variables.md for reference
265 |     """
266 | 
267 |     name: Optional[str] = Field(
268 |         None,
269 |         description="Variable set name",
270 |         min_length=1,
271 |         max_length=90,
272 |     )
273 |     description: Optional[str] = Field(
274 |         None,
275 |         description="Description of the variable set",
276 |         max_length=512,
277 |     )
278 |     global_: Optional[bool] = Field(
279 |         None,
280 |         alias="global",
281 |         description="Whether this is a global variable set",
282 |     )
283 |     priority: Optional[bool] = Field(
284 |         None,
285 |         description="Whether this variable set takes priority over workspace variables",
286 |     )
287 | 
288 | 
289 | class VariableSetCreateRequest(APIRequest):
290 |     """Request model for creating variable sets.
291 | 
292 |     Used for POST /organizations/:organization/varsets endpoint.
293 | 
294 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets
295 | 
296 |     See:
297 |         docs/models/variables.md for reference
298 |     """
299 | 
300 |     organization: str = Field(
301 |         ...,
302 |         description="The organization name",
303 |         min_length=1,
304 |     )
305 |     name: str = Field(
306 |         ...,
307 |         description="Variable set name",
308 |         min_length=1,
309 |         max_length=90,
310 |     )
311 |     params: Optional[VariableSetParams] = Field(
312 |         None,
313 |         description="Additional variable set parameters",
314 |     )
315 | 
316 | 
317 | class VariableSetUpdateRequest(APIRequest):
318 |     """Request model for updating variable sets.
319 | 
320 |     Used for PATCH /varsets/:varset_id endpoint.
321 | 
322 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets
323 | 
324 |     See:
325 |         docs/models/variables.md for reference
326 |     """
327 | 
328 |     varset_id: str = Field(
329 |         ...,
330 |         description="The variable set ID",
331 |         pattern=r"^varset-[a-zA-Z0-9]{16}$",
332 |     )
333 |     params: Optional[VariableSetParams] = Field(
334 |         None,
335 |         description="Variable set parameters to update",
336 |     )
337 | 
338 | 
339 | class VariableSetVariable(APIRequest):
340 |     """Model for variables within a variable set.
341 | 
342 |     Represents a variable that belongs to a variable set with the same
343 |     structure as workspace variables.
344 | 
345 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets
346 | 
347 |     See:
348 |         docs/models/variables.md for reference
349 |     """
350 | 
351 |     key: str = Field(
352 |         ...,
353 |         description="Variable name/key",
354 |         min_length=1,
355 |         max_length=255,
356 |     )
357 |     value: Optional[str] = Field(
358 |         None,
359 |         description="Variable value",
360 |         max_length=256000,
361 |     )
362 |     description: Optional[str] = Field(
363 |         None,
364 |         description="Description of the variable",
365 |         max_length=512,
366 |     )
367 |     category: VariableCategory = Field(
368 |         ...,
369 |         description="Variable category (terraform or env)",
370 |     )
371 |     hcl: Optional[bool] = Field(
372 |         False,
373 |         description="Whether the value is HCL code (only valid for terraform variables)",
374 |     )
375 |     sensitive: Optional[bool] = Field(
376 |         False,
377 |         description="Whether the variable value is sensitive",
378 |     )
379 | 
380 | 
381 | class VariableSetAssignmentRequest(APIRequest):
382 |     """Request model for assigning variable sets to workspaces or projects.
383 | 
384 |     Used for POST /varsets/:varset_id/relationships/workspaces or projects endpoints.
385 | 
386 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets
387 | 
388 |     See:
389 |         docs/models/variables.md for reference
390 |     """
391 | 
392 |     varset_id: str = Field(
393 |         ...,
394 |         description="The variable set ID",
395 |         pattern=r"^varset-[a-zA-Z0-9]{16}$",
396 |     )
397 |     workspace_ids: Optional[List[str]] = Field(
398 |         None,
399 |         description="List of workspace IDs to assign the variable set to",
400 |     )
401 |     project_ids: Optional[List[str]] = Field(
402 |         None,
403 |         description="List of project IDs to assign the variable set to",
404 |     )
405 | 
406 | 
407 | # Variable Set Variables Models
408 | 
409 | 
410 | class VariableSetVariableParams(APIRequest):
411 |     """Parameters for variable set variable operations without routing fields.
412 | 
413 |     This model provides all optional parameters for creating or updating variables
414 |     within variable sets, separating configuration parameters from routing information
415 |     like variable set ID and variable ID.
416 | 
417 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets
418 | 
419 |     See:
420 |         docs/models/variables.md for reference
421 |     """
422 | 
423 |     key: Optional[str] = Field(
424 |         None,
425 |         description="Variable name/key",
426 |         min_length=1,
427 |         max_length=255,
428 |     )
429 |     value: Optional[str] = Field(
430 |         None,
431 |         description="Variable value",
432 |         max_length=256000,
433 |     )
434 |     description: Optional[str] = Field(
435 |         None,
436 |         description="Description of the variable",
437 |         max_length=512,
438 |     )
439 |     category: Optional[VariableCategory] = Field(
440 |         None,
441 |         description="Variable category (terraform or env)",
442 |     )
443 |     hcl: Optional[bool] = Field(
444 |         None,
445 |         description="Whether the value is HCL code (only valid for terraform variables)",
446 |     )
447 |     sensitive: Optional[bool] = Field(
448 |         None,
449 |         description="Whether the variable value is sensitive",
450 |     )
451 | 
452 | 
453 | # List Request Models
454 | 
455 | 
456 | class VariableSetListRequest(APIRequest):
457 |     """Request model for listing variable sets.
458 | 
459 |     Used for GET /organizations/:organization/varsets endpoint.
460 | 
461 |     Reference: https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets
462 | 
463 |     See:
464 |         docs/models/variables.md for reference
465 |     """
466 | 
467 |     organization: str = Field(
468 |         ...,
469 |         description="The organization name",
470 |         min_length=1,
471 |     )
472 |     page_number: int = Field(
473 |         1,
474 |         description="The page number to return",
475 |         ge=1,
476 |     )
477 |     page_size: int = Field(
478 |         20,
479 |         description="The number of items per page",
480 |         ge=1,
481 |         le=100,
482 |     )
483 | 
```

--------------------------------------------------------------------------------
/docs/conversations/runs-management-conversation.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Run Management - Example Conversations
  2 | 
  3 | This document shows example conversations with Claude using the Terraform Cloud MCP run management features.
  4 | 
  5 | ## Creating and Managing Runs
  6 | 
  7 | ```
  8 | **User**: Create a plan for my "production" workspace
  9 | 
 10 | **Claude**: I'll create a plan-only run in your "production" workspace.
 11 | 
 12 | [Claude uses get_workspace_details tool to find the production workspace]
 13 | [Claude uses create_run tool with plan_only=True]
 14 | 
 15 | I've created a plan-only run in the "production" workspace. Here are the details:
 16 | 
 17 | **Run Details:**
 18 | - Run ID: run-J7cW8p2qRmYx3Dkv
 19 | - Status: Pending
 20 | - Created by: Your account ([email protected])
 21 | - Message: "Plan requested via Claude"
 22 | - Type: Plan only (will not auto-apply)
 23 | 
 24 | The run has been queued and will start shortly. Since this is a plan-only run, you'll need to review the plan output before applying any changes. I'll let you know when the plan is complete.
 25 | ```
 26 | 
 27 | ```
 28 | **User**: Create a destroy plan for "dev-test" workspace
 29 | 
 30 | **Claude**: I'll create a destroy plan for your "dev-test" workspace.
 31 | 
 32 | [Claude uses get_workspace_details tool to find the dev-test workspace]
 33 | [Claude uses create_run tool with is_destroy=True and plan_only=True]
 34 | 
 35 | I've created a destroy plan in the "dev-test" workspace. Here are the details:
 36 | 
 37 | **Run Details:**
 38 | - Run ID: run-L2tP6k8xZnQv1Bmj
 39 | - Status: Pending
 40 | - Created by: Your account ([email protected])
 41 | - Message: "Destroy plan requested via Claude"
 42 | - Type: Destroy plan (will delete all resources)
 43 | - Auto-apply: No (plan only)
 44 | 
 45 | This run will create a plan to destroy all resources managed by the "dev-test" workspace. Since this is a plan-only run, you'll need to review and explicitly approve the destruction before any resources are deleted.
 46 | ```
 47 | 
 48 | ```
 49 | **User**: Run a targeted plan in "staging" that only affects the database resources
 50 | 
 51 | **Claude**: I'll create a targeted plan in the "staging" workspace that only affects database resources.
 52 | 
 53 | [Claude uses get_workspace_details tool to find the staging workspace]
 54 | [Claude uses create_run tool with target_addrs for database resources]
 55 | 
 56 | I've created a targeted plan in the "staging" workspace that will only affect database resources. Here are the details:
 57 | 
 58 | **Run Details:**
 59 | - Run ID: run-K3jR7m9zXpYw2Ctn
 60 | - Status: Pending
 61 | - Created by: Your account ([email protected])
 62 | - Message: "Targeted plan for database resources only"
 63 | - Type: Plan
 64 | - Targets: 
 65 |   - module.database
 66 |   - aws_rds_cluster.main
 67 |   - aws_rds_instance.replicas
 68 | 
 69 | The run has been queued and will start shortly. This plan will only show changes related to the database resources you specified. Other resources in the workspace will not be affected by this run.
 70 | ```
 71 | 
 72 | ```
 73 | **User**: Create a plan with custom variables in the "development" workspace
 74 | 
 75 | **Claude**: I'll create a run with custom variables in the "development" workspace.
 76 | 
 77 | [Claude uses get_workspace_details tool to find the development workspace]
 78 | [Claude uses create_run tool with custom variables for environment, instance_type, and enable_monitoring]
 79 | 
 80 | I've created a plan in the "development" workspace with the custom variables you specified. Here are the details:
 81 | 
 82 | **Run Details:**
 83 | - Run ID: run-P8vT5q2nWxYz1Fmb
 84 | - Status: Pending
 85 | - Created by: Your account ([email protected])
 86 | - Message: "Plan with custom variable values"
 87 | 
 88 | **Custom Variables for this Run:**
 89 | - environment = "dev"
 90 | - instance_type = "t3.large"
 91 | - enable_monitoring = "true"
 92 | 
 93 | These custom variable values will override the workspace's default values for this specific run only. The run has been queued and will start shortly.
 94 | ```
 95 | 
 96 | ```
 97 | **User**: Create a run in "sandbox" workspace with auto-apply enabled
 98 | 
 99 | **Claude**: I'll create a run with auto-apply enabled in the "sandbox" workspace.
100 | 
101 | [Claude uses get_workspace_details tool to find the sandbox workspace]
102 | [Claude uses create_run tool with auto_apply=True]
103 | 
104 | I've created a run with auto-apply enabled in the "sandbox" workspace. Here are the details:
105 | 
106 | **Run Details:**
107 | - Run ID: run-Q9wU6r3oZyXa2Gnd
108 | - Status: Pending
109 | - Created by: Your account ([email protected])
110 | - Message: "Run with auto-apply enabled"
111 | - Auto-apply: Yes (will automatically apply after successful plan)
112 | 
113 | The run has been queued and will start shortly. Since auto-apply is enabled for this run, it will automatically apply the changes after the plan completes successfully, without requiring manual approval.
114 | ```
115 | 
116 | ## Listing and Viewing Runs
117 | 
118 | ```
119 | **User**: List all runs in my "production" workspace
120 | 
121 | **Claude**: I'll list all runs in your "production" workspace.
122 | 
123 | [Claude uses get_workspace_details tool to find the production workspace]
124 | [Claude uses list_runs_in_workspace tool to get all runs]
125 | 
126 | Here are the recent runs in your "production" workspace:
127 | 
128 | 1. **run-J7cW8p2qRmYx3Dkv** - "Plan requested via Claude"
129 |    - Created: 10 minutes ago
130 |    - Status: Planned (awaiting approval)
131 |    - Created by: You ([email protected])
132 |    - Type: Plan only
133 | 
134 | 2. **run-K4jR7p9qZnYw2Lmp** - "Weekly infrastructure update"
135 |    - Created: Yesterday at 14:32
136 |    - Status: Applied
137 |    - Created by: CI/CD Pipeline
138 |    - Changes: 3 to add, 1 to change, 0 to destroy
139 | 
140 | 3. **run-L5kS8q1rAoZx3Mnq** - "Security patch application"
141 |    - Created: 3 days ago
142 |    - Status: Applied
143 |    - Created by: [email protected]
144 |    - Changes: 0 to add, 5 to change, 0 to destroy
145 | 
146 | 4. **run-M6lT9r2sBpAy4Nod** - "Roll back configuration change"
147 |    - Created: 5 days ago
148 |    - Status: Discarded
149 |    - Created by: [email protected]
150 |    - Changes: 0 to add, 3 to change, 0 to destroy
151 | 
152 | 5. **run-N7mU0s3tCqBz5Ope** - "Add new monitoring resources"
153 |    - Created: 7 days ago
154 |    - Status: Applied
155 |    - Created by: You ([email protected])
156 |    - Changes: 8 to add, 0 to change, 0 to destroy
157 | ```
158 | 
159 | ```
160 | **User**: Show me runs in "example-org" that have errored in the last month
161 | 
162 | **Claude**: I'll find runs in the "example-org" organization that have errored in the last month.
163 | 
164 | [Claude uses list_runs_in_organization tool with filter_status="errored"]
165 | 
166 | I found the following runs in "example-org" that have errored in the last month:
167 | 
168 | 1. **run-P8vT5q2nWxYz1Fmb** - "Plan with custom variable values"
169 |    - Workspace: development
170 |    - Created: Today at 09:45
171 |    - Status: Errored (Planning failed)
172 |    - Error: "Invalid value for variable 'instance_type'"
173 | 
174 | 2. **run-S9pV6u3rDsEa8Ijf** - "Deploy new database resources"
175 |    - Workspace: prod-db-cluster
176 |    - Created: Yesterday at 18:22
177 |    - Status: Errored (Apply failed)
178 |    - Error: "Error creating RDS instance: InsufficientDBInstanceCapacity"
179 | 
180 | 3. **run-T0qW7v4sEtFb9Jkg** - "Update network configuration"
181 |    - Workspace: network-infra
182 |    - Created: 3 days ago
183 |    - Status: Errored (Planning failed)
184 |    - Error: "Provider configuration not found for aws"
185 | 
186 | 4. **run-U1rX8w5tFuGc0Klh** - "Scale up application servers"
187 |    - Workspace: app-servers
188 |    - Created: 5 days ago
189 |    - Status: Errored (Apply failed)
190 |    - Error: "Error applying Auto Scaling configuration: ValidationError"
191 | 
192 | 5. **run-V2sY9x6uGvHd1Lmi** - "Security patch deployment"
193 |    - Workspace: security-baseline
194 |    - Created: 2 weeks ago
195 |    - Status: Errored (Planning timed out)
196 |    - Error: "Terraform operation timed out after 1 hour"
197 | ```
198 | 
199 | ```
200 | **User**: Find all destroy plan runs in my organization
201 | 
202 | **Claude**: I'll find all destroy plan runs in your organization.
203 | 
204 | [Claude uses list_runs_in_organization tool to search for destroy runs across all workspaces]
205 | 
206 | Here are the destroy plan runs I found in the "example-org" organization:
207 | 
208 | 1. **run-L2tP6k8xZnQv1Bmj** - "Destroy plan requested via Claude"
209 |    - Workspace: dev-test
210 |    - Created: Today at 09:32
211 |    - Status: Planned (awaiting approval)
212 |    - Type: Destroy (will delete all resources)
213 |    - Created by: You ([email protected])
214 | 
215 | 2. **run-W3tZ0y7vHwIe2Mnj** - "Decommission test environment"
216 |    - Workspace: feature-test
217 |    - Created: 3 days ago
218 |    - Status: Applied
219 |    - Type: Destroy (deleted all resources)
220 |    - Created by: [email protected]
221 |    - Result: 0 to add, 0 to change, 27 to destroy
222 | 
223 | 3. **run-X4uA1z8wIxJf3Nok** - "Clean up temporary resources"
224 |    - Workspace: sandbox
225 |    - Created: 1 week ago
226 |    - Status: Applied
227 |    - Type: Destroy (partial)
228 |    - Created by: [email protected]
229 |    - Result: 0 to add, 0 to change, 5 to destroy
230 | 
231 | 4. **run-Y5vB2a9xJyKg4Opl** - "Remove deprecated services"
232 |    - Workspace: legacy-systems
233 |    - Created: 2 weeks ago
234 |    - Status: Discarded
235 |    - Type: Destroy (partial)
236 |    - Created by: CI/CD Pipeline
237 | ```
238 | 
239 | ```
240 | **User**: Get details for run ID "run-J7cW8p2qRmYx3Dkv"
241 | 
242 | **Claude**: I'll get the details for run ID "run-J7cW8p2qRmYx3Dkv".
243 | 
244 | [Claude uses get_run_details tool with the specified run ID]
245 | 
246 | Here are the details for run ID "run-J7cW8p2qRmYx3Dkv":
247 | 
248 | **Basic Information:**
249 | - Run ID: run-J7cW8p2qRmYx3Dkv
250 | - Status: Planned and finished (awaiting approval)
251 | - Message: "Plan requested via Claude"
252 | - Created: Today at 09:30 (10 minutes ago)
253 | - Created by: You ([email protected])
254 | 
255 | **Workspace:**
256 | - Name: production
257 | - Organization: example-org
258 | - Terraform Version: 1.5.2
259 | 
260 | **Plan Details:**
261 | - Resources to add: 2
262 | - Resources to change: 1
263 | - Resources to destroy: 0
264 | - Changes summary:
265 |   - Adding 2 AWS Lambda functions
266 |   - Updating IAM role permissions
267 | 
268 | **Phases:**
269 | - Plan started: Today at 09:30:15
270 | - Plan completed: Today at 09:31:45
271 | - Plan duration: 90 seconds
272 | - Apply phase: Awaiting approval
273 | 
274 | **Configuration:**
275 | - VCS commit: 7a8b9c0d... (feat: add new lambda functions)
276 | - Plan only: Yes (requires manual apply)
277 | - Auto-apply: No
278 | - Terraform Version: 1.5.2
279 | - Working directory: /terraform
280 | 
281 | The run is currently awaiting your approval to apply the plan. You can apply it using the apply_run function with this run ID.
282 | ```
283 | 
284 | ## Run Actions
285 | 
286 | ```
287 | **User**: Apply the pending run for "staging" workspace
288 | 
289 | **Claude**: I'll apply the pending run for the "staging" workspace.
290 | 
291 | [Claude uses list_runs_in_workspace tool to find pending runs in staging workspace]
292 | [Claude uses apply_run tool with a review comment]
293 | 
294 | I've applied the pending run (run-K3jR7m9zXpYw2Ctn) in the "staging" workspace. Here's the status:
295 | 
296 | **Apply Initiated:**
297 | - Run ID: run-K3jR7m9zXpYw2Ctn
298 | - Status: Applying
299 | - Comment: "Applied via Claude after review"
300 | - Action taken: Apply started
301 | 
302 | The run is now applying the planned changes to your infrastructure. The apply process typically takes a few minutes to complete. The targeted changes to your database resources are now being executed.
303 | ```
304 | 
305 | ```
306 | **User**: Cancel the run "run-P8vT5q2nWxYz1Fmb", it's taking too long
307 | 
308 | **Claude**: I'll cancel the run "run-P8vT5q2nWxYz1Fmb" that's taking too long.
309 | 
310 | [Claude uses cancel_run tool with the specified run ID and cancellation reason]
311 | 
312 | I've initiated the cancellation of run "run-P8vT5q2nWxYz1Fmb". Here's the status:
313 | 
314 | **Cancellation Initiated:**
315 | - Run ID: run-P8vT5q2nWxYz1Fmb
316 | - Status: Cancelling
317 | - Comment: "Cancelled due to long execution time"
318 | 
319 | The system is now gracefully stopping the run. It may take a moment to completely cancel as Terraform needs to clean up any in-progress operations. Once cancelled, the workspace will be unlocked and available for new runs.
320 | ```
321 | 
322 | ```
323 | **User**: Discard the plan for the "dev" workspace, those changes aren't needed
324 | 
325 | **Claude**: I'll discard the pending plan for the "dev" workspace.
326 | 
327 | [Claude uses list_runs_in_workspace tool to find pending runs in dev workspace]
328 | [Claude uses discard_run tool with reason for discarding]
329 | 
330 | I've discarded the pending plan (run-Z6wC3b0yKzLh5Pqm) in the "dev" workspace. Here's the confirmation:
331 | 
332 | **Plan Discarded:**
333 | - Run ID: run-Z6wC3b0yKzLh5Pqm
334 | - Status: Discarded
335 | - Comment: "Changes no longer needed"
336 | - Created by: You ([email protected])
337 | 
338 | The plan has been discarded and will not be applied. The workspace is now unlocked and available for new runs. No changes were made to your infrastructure.
339 | ```
340 | 
341 | ```
342 | **User**: Force cancel the stuck run in "production"
343 | 
344 | **Claude**: I'll force cancel the stuck run in the "production" workspace.
345 | 
346 | [Claude uses list_runs_in_workspace tool to find running runs in production workspace]
347 | [Claude uses cancel_run tool first, then force_cancel_run tool for the stuck run]
348 | 
349 | I've initiated a force cancel for the stuck run (run-A7xD4c1zLaMe6Rqn) in the "production" workspace. Here's the status:
350 | 
351 | **Force Cancellation Initiated:**
352 | - Run ID: run-A7xD4c1zLaMe6Rqn
353 | - Status: Force cancelling
354 | - Comment: "Force cancelling stuck run"
355 | 
356 | I first attempted a normal cancel operation, and then proceeded with the force cancel to immediately terminate the run. This will immediately unlock the workspace, allowing you to queue new runs. Note that force cancelling may leave some Terraform state operations incomplete, but it's necessary when a run is truly stuck.
357 | ```
358 | 
359 | ```
360 | **User**: I need to execute this run immediately, force execute it
361 | 
362 | **Claude**: I'll force execute a run to bypass the queue and start it immediately.
363 | 
364 | [Claude uses list_runs_in_organization tool to find pending runs in the queue]
365 | [Claude uses force_execute_run tool to prioritize the run]
366 | 
367 | I've force executed the pending run (run-B8yE5d2aLbNf7Sro). Here's what happened:
368 | 
369 | **Force Execution Initiated:**
370 | - Run ID: run-B8yE5d2aLbNf7Sro
371 | - Status: Running (Planning)
372 | - Workspace: deployment
373 | - Original position: #3 in queue
374 | 
375 | The force execute command:
376 | 1. Cancelled all prior runs that were blocking this run
377 | 2. Unlocked the workspace
378 | 3. Started this run immediately
379 | 
380 | The run is now actively planning and has bypassed the queue. This is useful in urgent situations, but should be used sparingly as it cancels other queued runs.
381 | ```
```

--------------------------------------------------------------------------------
/docs/tools/variables.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Variable Tools
  2 | 
  3 | This module provides tools for managing variables and variable sets in Terraform Cloud.
  4 | 
  5 | ## Overview
  6 | 
  7 | Variables in Terraform Cloud are used to provide inputs to your Terraform configurations and set environment variables during runs. These tools allow you to manage variables at the workspace level and create reusable variable sets that can be shared across multiple workspaces and projects.
  8 | 
  9 | ## API Reference
 10 | 
 11 | These tools interact with the Terraform Cloud Variables API:
 12 | - [Workspace Variables API Documentation](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspace-variables)
 13 | - [Variable Sets API Documentation](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/variable-sets)
 14 | - [Variables in Terraform Cloud](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/variables)
 15 | 
 16 | ## Tools Reference
 17 | 
 18 | ### list_workspace_variables
 19 | 
 20 | **Function:** `list_workspace_variables(workspace_id: str) -> Dict[str, Any]`
 21 | 
 22 | **Description:** Retrieves all variables (both Terraform and environment) configured for a specific workspace.
 23 | 
 24 | **Parameters:**
 25 | - `workspace_id` (str): The ID of the workspace (format: "ws-xxxxxxxx")
 26 | 
 27 | **Returns:** JSON response containing list of workspace variables with their configuration and values.
 28 | 
 29 | **Notes:**
 30 | - Requires "read variables" permission on the workspace
 31 | - Sensitive variable values are not returned in the response
 32 | - Both Terraform and environment variables are included
 33 | 
 34 | ### create_workspace_variable
 35 | 
 36 | **Function:** `create_workspace_variable(workspace_id: str, key: str, category: str, params: Optional[WorkspaceVariableParams] = None) -> Dict[str, Any]`
 37 | 
 38 | **Description:** Creates a new Terraform or environment variable within a workspace.
 39 | 
 40 | **Parameters:**
 41 | - `workspace_id` (str): The ID of the workspace (format: "ws-xxxxxxxx")
 42 | - `key` (str): The variable name/key
 43 | - `category` (str): Variable category ("terraform" or "env")
 44 | - `params` (WorkspaceVariableParams, optional): Additional variable parameters including value, description, HCL format, and sensitivity settings
 45 | 
 46 | **Returns:** JSON response with the created variable including its configuration and metadata.
 47 | 
 48 | **Notes:**
 49 | - Requires "write variables" permission on the workspace
 50 | - HCL format is only valid for terraform category variables
 51 | - Sensitive variables will have their values hidden in responses
 52 | 
 53 | ### update_workspace_variable
 54 | 
 55 | **Function:** `update_workspace_variable(workspace_id: str, variable_id: str, params: Optional[WorkspaceVariableParams] = None) -> Dict[str, Any]`
 56 | 
 57 | **Description:** Modifies the configuration of an existing workspace variable. Only specified attributes will be updated.
 58 | 
 59 | **Parameters:**
 60 | - `workspace_id` (str): The ID of the workspace (format: "ws-xxxxxxxx")
 61 | - `variable_id` (str): The ID of the variable (format: "var-xxxxxxxx")
 62 | - `params` (WorkspaceVariableParams, optional): Variable parameters to update including key, value, description, category, HCL format, and sensitivity
 63 | 
 64 | **Returns:** JSON response with the updated variable including all current settings.
 65 | 
 66 | **Notes:**
 67 | - Requires "write variables" permission on the workspace
 68 | - Only specified attributes are updated; others remain unchanged
 69 | - Cannot change a sensitive variable to non-sensitive
 70 | 
 71 | ### delete_workspace_variable
 72 | 
 73 | **Function:** `delete_workspace_variable(workspace_id: str, variable_id: str) -> Dict[str, Any]`
 74 | 
 75 | **Description:** Permanently removes a variable from a workspace. This action cannot be undone.
 76 | 
 77 | **Parameters:**
 78 | - `workspace_id` (str): The ID of the workspace (format: "ws-xxxxxxxx")
 79 | - `variable_id` (str): The ID of the variable (format: "var-xxxxxxxx")
 80 | 
 81 | **Returns:** Empty response with HTTP 204 status code if successful.
 82 | 
 83 | **Notes:**
 84 | - DESTRUCTIVE OPERATION: Requires `ENABLE_DELETE_TOOLS=true` environment variable
 85 | - Requires "write variables" permission on the workspace
 86 | - This action cannot be undone
 87 | 
 88 | ### list_variable_sets
 89 | 
 90 | **Function:** `list_variable_sets(organization: str, page_number: int = 1, page_size: int = 20) -> Dict[str, Any]`
 91 | 
 92 | **Description:** Retrieves a paginated list of all variable sets in a Terraform Cloud organization.
 93 | 
 94 | **Parameters:**
 95 | - `organization` (str): The name of the organization
 96 | - `page_number` (int, optional): The page number to return (default: 1)
 97 | - `page_size` (int, optional): Number of items per page (default: 20, max: 100)
 98 | 
 99 | **Returns:** JSON response containing paginated list of variable sets with their configuration and metadata.
100 | 
101 | **Notes:**
102 | - Requires "read variable sets" permission on the organization
103 | - Variable sets allow you to reuse variables across multiple workspaces
104 | - Results are paginated with metadata indicating total count
105 | 
106 | ### get_variable_set
107 | 
108 | **Function:** `get_variable_set(varset_id: str) -> Dict[str, Any]`
109 | 
110 | **Description:** Retrieves comprehensive information about a variable set including its variables, workspace assignments, and configuration.
111 | 
112 | **Parameters:**
113 | - `varset_id` (str): The ID of the variable set (format: "varset-xxxxxxxx")
114 | 
115 | **Returns:** JSON response with variable set details including configuration and relationships.
116 | 
117 | **Notes:**
118 | - Requires "read variable sets" permission
119 | - Includes information about workspace and project assignments
120 | - Shows global status and priority settings
121 | 
122 | ### create_variable_set
123 | 
124 | **Function:** `create_variable_set(organization: str, name: str, params: Optional[VariableSetParams] = None) -> Dict[str, Any]`
125 | 
126 | **Description:** Creates a new variable set which can be used to manage variables across multiple workspaces and projects.
127 | 
128 | **Parameters:**
129 | - `organization` (str): The name of the organization
130 | - `name` (str): The name to give the variable set
131 | - `params` (VariableSetParams, optional): Additional variable set parameters including description, global status, and priority settings
132 | 
133 | **Returns:** JSON response with the created variable set including its configuration and metadata.
134 | 
135 | **Notes:**
136 | - Requires "write variable sets" permission on the organization
137 | - Global variable sets are automatically applied to all workspaces
138 | - Priority variable sets override workspace-level variables
139 | 
140 | ### update_variable_set
141 | 
142 | **Function:** `update_variable_set(varset_id: str, params: Optional[VariableSetParams] = None) -> Dict[str, Any]`
143 | 
144 | **Description:** Modifies the settings of a variable set. Only specified attributes will be updated.
145 | 
146 | **Parameters:**
147 | - `varset_id` (str): The ID of the variable set (format: "varset-xxxxxxxx")
148 | - `params` (VariableSetParams, optional): Variable set parameters to update including name, description, global status, and priority
149 | 
150 | **Returns:** JSON response with the updated variable set including all current settings.
151 | 
152 | **Notes:**
153 | - Requires "write variable sets" permission
154 | - Only specified attributes are updated; others remain unchanged
155 | - Changing global status affects workspace assignments
156 | 
157 | ### delete_variable_set
158 | 
159 | **Function:** `delete_variable_set(varset_id: str) -> Dict[str, Any]`
160 | 
161 | **Description:** Permanently removes a variable set and all its variables. The variable set will be unassigned from all workspaces and projects.
162 | 
163 | **Parameters:**
164 | - `varset_id` (str): The ID of the variable set (format: "varset-xxxxxxxx")
165 | 
166 | **Returns:** Empty response with HTTP 204 status code if successful.
167 | 
168 | **Notes:**
169 | - DESTRUCTIVE OPERATION: Requires `ENABLE_DELETE_TOOLS=true` environment variable
170 | - Requires "write variable sets" permission
171 | - This action cannot be undone and removes all variables in the set
172 | 
173 | ### assign_variable_set_to_workspaces
174 | 
175 | **Function:** `assign_variable_set_to_workspaces(varset_id: str, workspace_ids: List[str]) -> Dict[str, Any]`
176 | 
177 | **Description:** Makes the variables in a variable set available to the specified workspaces.
178 | 
179 | **Parameters:**
180 | - `varset_id` (str): The ID of the variable set (format: "varset-xxxxxxxx")
181 | - `workspace_ids` (List[str]): List of workspace IDs (format: ["ws-xxxxxxxx", ...])
182 | 
183 | **Returns:** Empty response with HTTP 204 status code if successful.
184 | 
185 | **Notes:**
186 | - Variables from variable sets take precedence over workspace variables if the variable set has priority enabled
187 | - Does not affect global variable sets (they're automatically applied)
188 | 
189 | ### unassign_variable_set_from_workspaces
190 | 
191 | **Function:** `unassign_variable_set_from_workspaces(varset_id: str, workspace_ids: List[str]) -> Dict[str, Any]`
192 | 
193 | **Description:** Removes the variable set assignment from the specified workspaces. The variables will no longer be available in those workspaces.
194 | 
195 | **Parameters:**
196 | - `varset_id` (str): The ID of the variable set (format: "varset-xxxxxxxx")
197 | - `workspace_ids` (List[str]): List of workspace IDs (format: ["ws-xxxxxxxx", ...])
198 | 
199 | **Returns:** Empty response with HTTP 204 status code if successful.
200 | 
201 | **Notes:**
202 | - Cannot unassign global variable sets from workspaces
203 | - Variables become unavailable immediately in the affected workspaces
204 | 
205 | ### assign_variable_set_to_projects
206 | 
207 | **Function:** `assign_variable_set_to_projects(varset_id: str, project_ids: List[str]) -> Dict[str, Any]`
208 | 
209 | **Description:** Makes the variables in a variable set available to all workspaces within the specified projects.
210 | 
211 | **Parameters:**
212 | - `varset_id` (str): The ID of the variable set (format: "varset-xxxxxxxx")
213 | - `project_ids` (List[str]): List of project IDs (format: ["prj-xxxxxxxx", ...])
214 | 
215 | **Returns:** Empty response with HTTP 204 status code if successful.
216 | 
217 | **Notes:**
218 | - All workspaces in the project receive the variable set
219 | - New workspaces added to the project will automatically inherit the variable set
220 | 
221 | ### unassign_variable_set_from_projects
222 | 
223 | **Function:** `unassign_variable_set_from_projects(varset_id: str, project_ids: List[str]) -> Dict[str, Any]`
224 | 
225 | **Description:** Removes the variable set assignment from the specified projects. The variables will no longer be available in workspaces within those projects.
226 | 
227 | **Parameters:**
228 | - `varset_id` (str): The ID of the variable set (format: "varset-xxxxxxxx")
229 | - `project_ids` (List[str]): List of project IDs (format: ["prj-xxxxxxxx", ...])
230 | 
231 | **Returns:** Empty response with HTTP 204 status code if successful.
232 | 
233 | **Notes:**
234 | - Affects all workspaces within the specified projects
235 | - Cannot unassign global variable sets from projects
236 | 
237 | ### list_variables_in_variable_set
238 | 
239 | **Function:** `list_variables_in_variable_set(varset_id: str) -> Dict[str, Any]`
240 | 
241 | **Description:** Retrieves all variables that belong to a specific variable set, including their configuration and values.
242 | 
243 | **Parameters:**
244 | - `varset_id` (str): The ID of the variable set (format: "varset-xxxxxxxx")
245 | 
246 | **Returns:** JSON response containing list of variables in the variable set with their configuration.
247 | 
248 | **Notes:**
249 | - Requires "read variable sets" permission
250 | - Sensitive variable values are not returned in the response
251 | - Both Terraform and environment variables are included
252 | 
253 | ### create_variable_in_variable_set
254 | 
255 | **Function:** `create_variable_in_variable_set(varset_id: str, key: str, category: str, params: Optional[VariableSetVariableParams] = None) -> Dict[str, Any]`
256 | 
257 | **Description:** Creates a new Terraform or environment variable within a variable set.
258 | 
259 | **Parameters:**
260 | - `varset_id` (str): The ID of the variable set (format: "varset-xxxxxxxx")
261 | - `key` (str): The variable name/key
262 | - `category` (str): Variable category ("terraform" or "env")
263 | - `params` (VariableSetVariableParams, optional): Additional variable parameters including value, description, HCL format, and sensitivity settings
264 | 
265 | **Returns:** JSON response with the created variable including its configuration and metadata.
266 | 
267 | **Notes:**
268 | - Requires "write variable sets" permission
269 | - HCL format is only valid for terraform category variables
270 | - Variable becomes available in all workspaces/projects assigned to the variable set
271 | 
272 | ### update_variable_in_variable_set
273 | 
274 | **Function:** `update_variable_in_variable_set(varset_id: str, var_id: str, params: Optional[VariableSetVariableParams] = None) -> Dict[str, Any]`
275 | 
276 | **Description:** Modifies the configuration of an existing variable within a variable set. Only specified attributes will be updated.
277 | 
278 | **Parameters:**
279 | - `varset_id` (str): The ID of the variable set (format: "varset-xxxxxxxx")
280 | - `var_id` (str): The ID of the variable (format: "var-xxxxxxxx")
281 | - `params` (VariableSetVariableParams, optional): Variable parameters to update including key, value, description, category, HCL format, and sensitivity
282 | 
283 | **Returns:** JSON response with the updated variable including all current settings.
284 | 
285 | **Notes:**
286 | - Requires "write variable sets" permission
287 | - Only specified attributes are updated; others remain unchanged
288 | - Changes affect all workspaces using this variable set
289 | 
290 | ### delete_variable_from_variable_set
291 | 
292 | **Function:** `delete_variable_from_variable_set(varset_id: str, var_id: str) -> Dict[str, Any]`
293 | 
294 | **Description:** Permanently removes a variable from a variable set. This action cannot be undone.
295 | 
296 | **Parameters:**
297 | - `varset_id` (str): The ID of the variable set (format: "varset-xxxxxxxx")
298 | - `var_id` (str): The ID of the variable (format: "var-xxxxxxxx")
299 | 
300 | **Returns:** Empty response with HTTP 204 status code if successful.
301 | 
302 | **Notes:**
303 | - DESTRUCTIVE OPERATION: Requires `ENABLE_DELETE_TOOLS=true` environment variable
304 | - Requires "write variable sets" permission
305 | - This action cannot be undone
306 | - Variable becomes unavailable in all workspaces using this variable set
307 | 
308 | ## Common Error Scenarios
309 | 
310 | | Error | Description | Resolution |
311 | |-------|-------------|------------|
312 | | 401 Unauthorized | Invalid or missing authentication token | Verify TFC_TOKEN environment variable |
313 | | 403 Forbidden | Insufficient permissions for the operation | Check user/team permissions on workspace/organization |
314 | | 404 Not Found | Workspace, variable set, or variable not found | Verify the ID format and existence |
315 | | 422 Unprocessable Entity | Invalid variable configuration (e.g., HCL on env variable) | Review variable parameters and constraints |
316 | | 409 Conflict | Variable key already exists in workspace/variable set | Use a different key or update the existing variable |
```
Page 3/4FirstPrevNextLast