Coverage for mcp/resources/config.py: 88%

66 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-15 15:07 +0000

1"""Configuration resources (config:// scheme) for the GCO MCP server. 

2 

3Exposes the CDK configuration schema, feature toggles, environment variables, 

4and the cdk.json configuration matrix used by tests. 

5""" 

6 

7import json 

8from pathlib import Path 

9 

10from server import mcp 

11 

12PROJECT_ROOT = Path(__file__).parent.parent.parent 

13 

14 

15@mcp.resource("config://gco/index") 

16def config_index() -> str: 

17 """List configuration resources — CDK schema, feature toggles, env vars.""" 

18 lines = ["# GCO Configuration\n"] 

19 lines.append("## CDK Configuration") 

20 lines.append("- `config://gco/cdk.json` — Current CDK deployment configuration") 

21 lines.append("- `config://gco/feature-toggles` — All feature toggles and their defaults") 

22 lines.append( 

23 "- `config://gco/env-vars` — Environment variables used by the MCP server and services\n" 

24 ) 

25 lines.append("## Related") 

26 lines.append("- `source://gco/config/pyproject.toml` — Python project metadata") 

27 lines.append("- `source://gco/config/app.py` — CDK app entry point") 

28 lines.append("- `docs://gco/docs/CUSTOMIZATION` — Full customization guide") 

29 return "\n".join(lines) 

30 

31 

32@mcp.resource("config://gco/cdk.json") 

33def cdk_json_resource() -> str: 

34 """Read the current CDK deployment configuration.""" 

35 path = PROJECT_ROOT / "cdk.json" 

36 if not path.is_file(): 36 ↛ 37line 36 didn't jump to line 37 because the condition on line 36 was never true

37 return "cdk.json not found." 

38 return path.read_text() 

39 

40 

41@mcp.resource("config://gco/feature-toggles") 

42def feature_toggles_resource() -> str: 

43 """List all feature toggles available in cdk.json with their defaults. 

44 

45 This resource parses the current cdk.json and documents every 

46 configurable feature toggle so the LLM can help users enable/disable 

47 features. 

48 """ 

49 path = PROJECT_ROOT / "cdk.json" 

50 if not path.is_file(): 50 ↛ 51line 50 didn't jump to line 51 because the condition on line 50 was never true

51 return "cdk.json not found." 

52 

53 try: 

54 config = json.loads(path.read_text()) 

55 context = config.get("context", {}) 

56 except json.JSONDecodeError, KeyError: 

57 return "Could not parse cdk.json." 

58 

59 lines = ["# GCO Feature Toggles\n"] 

60 lines.append("These are the configurable options in `cdk.json` under the `context` key.\n") 

61 

62 # Extract known toggle categories 

63 if "regions" in context: 63 ↛ 64line 63 didn't jump to line 64 because the condition on line 63 was never true

64 lines.append(f"## Regions\n`regions`: {json.dumps(context['regions'])}\n") 

65 

66 helm = context.get("helm", {}) 

67 if helm: 67 ↛ 75line 67 didn't jump to line 75 because the condition on line 67 was always true

68 lines.append("## Helm Charts (Schedulers & Operators)\n") 

69 for chart, cfg in sorted(helm.items()): 

70 enabled = cfg.get("enabled", False) if isinstance(cfg, dict) else cfg 

71 lines.append(f"- `helm.{chart}.enabled`: {enabled}") 

72 lines.append("") 

73 

74 # Storage toggles 

75 for key in ("fsx", "valkey", "aurora_pgvector"): 

76 val = context.get(key, {}) 

77 if isinstance(val, dict): 77 ↛ 75line 77 didn't jump to line 75 because the condition on line 77 was always true

78 enabled = val.get("enabled", False) 

79 lines.append(f"## {key}\n- `{key}.enabled`: {enabled}") 

80 for k, v in sorted(val.items()): 

81 if k != "enabled": 

82 lines.append(f"- `{key}.{k}`: {v}") 

83 lines.append("") 

84 

85 # Resource quotas 

86 for key in ("manifest_processor", "queue_processor"): 

87 val = context.get(key, {}) 

88 if val: 88 ↛ 86line 88 didn't jump to line 86 because the condition on line 88 was always true

89 lines.append(f"## {key}\n") 

90 for k, v in sorted(val.items()): 

91 if isinstance(v, dict): 

92 for k2, v2 in sorted(v.items()): 

93 lines.append(f"- `{key}.{k}.{k2}`: {v2}") 

94 else: 

95 lines.append(f"- `{key}.{k}`: {v}") 

96 lines.append("") 

97 

98 return "\n".join(lines) 

99 

100 

101@mcp.resource("config://gco/env-vars") 

102def env_vars_resource() -> str: 

103 """List environment variables used by the GCO MCP server and services.""" 

104 return """# GCO Environment Variables 

105 

106## MCP Server 

107 

108| Variable | Default | Description | 

109|----------|---------|-------------| 

110| `GCO_MCP_ROLE_ARN` | (unset) | IAM role ARN to assume at startup. When set, the MCP server uses STS AssumeRole for least-privilege access. | 

111| `GCO_MCP_ROLE_SESSION_NAME` | `gco-mcp-server` | Session name for the assumed role. | 

112| `GCO_MCP_ROLE_DURATION_SECONDS` | `3600` | Duration in seconds for the assumed role credentials. | 

113| `GCO_ENABLE_CAPACITY_PURCHASE` | `false` | Set to `true` to enable the `reserve_capacity` tool (can incur AWS charges). | 

114 

115## CLI 

116 

117| Variable | Default | Description | 

118|----------|---------|-------------| 

119| `AWS_REGION` | (from config) | Default AWS region for CLI commands. | 

120| `AWS_PROFILE` | (default) | AWS CLI profile to use. | 

121| `GCO_CONFIG_PATH` | `cdk.json` | Path to the CDK configuration file. | 

122 

123## Services (Kubernetes) 

124 

125| Variable | Default | Description | 

126|----------|---------|-------------| 

127| `AUTH_SECRET_ARN` | (from stack) | Secrets Manager ARN for the authentication secret. | 

128| `CLUSTER_NAME` | (from stack) | EKS cluster name. | 

129| `JOB_QUEUE_URL` | (from stack) | SQS queue URL for job submission. | 

130| `DLQ_URL` | (from stack) | Dead letter queue URL. | 

131| `DYNAMODB_TABLE` | (from stack) | DynamoDB table name for job/template/webhook storage. | 

132"""