foundry-mcp 0.8.22__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of foundry-mcp might be problematic. Click here for more details.

Files changed (153) hide show
  1. foundry_mcp/__init__.py +13 -0
  2. foundry_mcp/cli/__init__.py +67 -0
  3. foundry_mcp/cli/__main__.py +9 -0
  4. foundry_mcp/cli/agent.py +96 -0
  5. foundry_mcp/cli/commands/__init__.py +37 -0
  6. foundry_mcp/cli/commands/cache.py +137 -0
  7. foundry_mcp/cli/commands/dashboard.py +148 -0
  8. foundry_mcp/cli/commands/dev.py +446 -0
  9. foundry_mcp/cli/commands/journal.py +377 -0
  10. foundry_mcp/cli/commands/lifecycle.py +274 -0
  11. foundry_mcp/cli/commands/modify.py +824 -0
  12. foundry_mcp/cli/commands/plan.py +640 -0
  13. foundry_mcp/cli/commands/pr.py +393 -0
  14. foundry_mcp/cli/commands/review.py +667 -0
  15. foundry_mcp/cli/commands/session.py +472 -0
  16. foundry_mcp/cli/commands/specs.py +686 -0
  17. foundry_mcp/cli/commands/tasks.py +807 -0
  18. foundry_mcp/cli/commands/testing.py +676 -0
  19. foundry_mcp/cli/commands/validate.py +982 -0
  20. foundry_mcp/cli/config.py +98 -0
  21. foundry_mcp/cli/context.py +298 -0
  22. foundry_mcp/cli/logging.py +212 -0
  23. foundry_mcp/cli/main.py +44 -0
  24. foundry_mcp/cli/output.py +122 -0
  25. foundry_mcp/cli/registry.py +110 -0
  26. foundry_mcp/cli/resilience.py +178 -0
  27. foundry_mcp/cli/transcript.py +217 -0
  28. foundry_mcp/config.py +1454 -0
  29. foundry_mcp/core/__init__.py +144 -0
  30. foundry_mcp/core/ai_consultation.py +1773 -0
  31. foundry_mcp/core/batch_operations.py +1202 -0
  32. foundry_mcp/core/cache.py +195 -0
  33. foundry_mcp/core/capabilities.py +446 -0
  34. foundry_mcp/core/concurrency.py +898 -0
  35. foundry_mcp/core/context.py +540 -0
  36. foundry_mcp/core/discovery.py +1603 -0
  37. foundry_mcp/core/error_collection.py +728 -0
  38. foundry_mcp/core/error_store.py +592 -0
  39. foundry_mcp/core/health.py +749 -0
  40. foundry_mcp/core/intake.py +933 -0
  41. foundry_mcp/core/journal.py +700 -0
  42. foundry_mcp/core/lifecycle.py +412 -0
  43. foundry_mcp/core/llm_config.py +1376 -0
  44. foundry_mcp/core/llm_patterns.py +510 -0
  45. foundry_mcp/core/llm_provider.py +1569 -0
  46. foundry_mcp/core/logging_config.py +374 -0
  47. foundry_mcp/core/metrics_persistence.py +584 -0
  48. foundry_mcp/core/metrics_registry.py +327 -0
  49. foundry_mcp/core/metrics_store.py +641 -0
  50. foundry_mcp/core/modifications.py +224 -0
  51. foundry_mcp/core/naming.py +146 -0
  52. foundry_mcp/core/observability.py +1216 -0
  53. foundry_mcp/core/otel.py +452 -0
  54. foundry_mcp/core/otel_stubs.py +264 -0
  55. foundry_mcp/core/pagination.py +255 -0
  56. foundry_mcp/core/progress.py +387 -0
  57. foundry_mcp/core/prometheus.py +564 -0
  58. foundry_mcp/core/prompts/__init__.py +464 -0
  59. foundry_mcp/core/prompts/fidelity_review.py +691 -0
  60. foundry_mcp/core/prompts/markdown_plan_review.py +515 -0
  61. foundry_mcp/core/prompts/plan_review.py +627 -0
  62. foundry_mcp/core/providers/__init__.py +237 -0
  63. foundry_mcp/core/providers/base.py +515 -0
  64. foundry_mcp/core/providers/claude.py +472 -0
  65. foundry_mcp/core/providers/codex.py +637 -0
  66. foundry_mcp/core/providers/cursor_agent.py +630 -0
  67. foundry_mcp/core/providers/detectors.py +515 -0
  68. foundry_mcp/core/providers/gemini.py +426 -0
  69. foundry_mcp/core/providers/opencode.py +718 -0
  70. foundry_mcp/core/providers/opencode_wrapper.js +308 -0
  71. foundry_mcp/core/providers/package-lock.json +24 -0
  72. foundry_mcp/core/providers/package.json +25 -0
  73. foundry_mcp/core/providers/registry.py +607 -0
  74. foundry_mcp/core/providers/test_provider.py +171 -0
  75. foundry_mcp/core/providers/validation.py +857 -0
  76. foundry_mcp/core/rate_limit.py +427 -0
  77. foundry_mcp/core/research/__init__.py +68 -0
  78. foundry_mcp/core/research/memory.py +528 -0
  79. foundry_mcp/core/research/models.py +1234 -0
  80. foundry_mcp/core/research/providers/__init__.py +40 -0
  81. foundry_mcp/core/research/providers/base.py +242 -0
  82. foundry_mcp/core/research/providers/google.py +507 -0
  83. foundry_mcp/core/research/providers/perplexity.py +442 -0
  84. foundry_mcp/core/research/providers/semantic_scholar.py +544 -0
  85. foundry_mcp/core/research/providers/tavily.py +383 -0
  86. foundry_mcp/core/research/workflows/__init__.py +25 -0
  87. foundry_mcp/core/research/workflows/base.py +298 -0
  88. foundry_mcp/core/research/workflows/chat.py +271 -0
  89. foundry_mcp/core/research/workflows/consensus.py +539 -0
  90. foundry_mcp/core/research/workflows/deep_research.py +4142 -0
  91. foundry_mcp/core/research/workflows/ideate.py +682 -0
  92. foundry_mcp/core/research/workflows/thinkdeep.py +405 -0
  93. foundry_mcp/core/resilience.py +600 -0
  94. foundry_mcp/core/responses.py +1624 -0
  95. foundry_mcp/core/review.py +366 -0
  96. foundry_mcp/core/security.py +438 -0
  97. foundry_mcp/core/spec.py +4119 -0
  98. foundry_mcp/core/task.py +2463 -0
  99. foundry_mcp/core/testing.py +839 -0
  100. foundry_mcp/core/validation.py +2357 -0
  101. foundry_mcp/dashboard/__init__.py +32 -0
  102. foundry_mcp/dashboard/app.py +119 -0
  103. foundry_mcp/dashboard/components/__init__.py +17 -0
  104. foundry_mcp/dashboard/components/cards.py +88 -0
  105. foundry_mcp/dashboard/components/charts.py +177 -0
  106. foundry_mcp/dashboard/components/filters.py +136 -0
  107. foundry_mcp/dashboard/components/tables.py +195 -0
  108. foundry_mcp/dashboard/data/__init__.py +11 -0
  109. foundry_mcp/dashboard/data/stores.py +433 -0
  110. foundry_mcp/dashboard/launcher.py +300 -0
  111. foundry_mcp/dashboard/views/__init__.py +12 -0
  112. foundry_mcp/dashboard/views/errors.py +217 -0
  113. foundry_mcp/dashboard/views/metrics.py +164 -0
  114. foundry_mcp/dashboard/views/overview.py +96 -0
  115. foundry_mcp/dashboard/views/providers.py +83 -0
  116. foundry_mcp/dashboard/views/sdd_workflow.py +255 -0
  117. foundry_mcp/dashboard/views/tool_usage.py +139 -0
  118. foundry_mcp/prompts/__init__.py +9 -0
  119. foundry_mcp/prompts/workflows.py +525 -0
  120. foundry_mcp/resources/__init__.py +9 -0
  121. foundry_mcp/resources/specs.py +591 -0
  122. foundry_mcp/schemas/__init__.py +38 -0
  123. foundry_mcp/schemas/intake-schema.json +89 -0
  124. foundry_mcp/schemas/sdd-spec-schema.json +414 -0
  125. foundry_mcp/server.py +150 -0
  126. foundry_mcp/tools/__init__.py +10 -0
  127. foundry_mcp/tools/unified/__init__.py +92 -0
  128. foundry_mcp/tools/unified/authoring.py +3620 -0
  129. foundry_mcp/tools/unified/context_helpers.py +98 -0
  130. foundry_mcp/tools/unified/documentation_helpers.py +268 -0
  131. foundry_mcp/tools/unified/environment.py +1341 -0
  132. foundry_mcp/tools/unified/error.py +479 -0
  133. foundry_mcp/tools/unified/health.py +225 -0
  134. foundry_mcp/tools/unified/journal.py +841 -0
  135. foundry_mcp/tools/unified/lifecycle.py +640 -0
  136. foundry_mcp/tools/unified/metrics.py +777 -0
  137. foundry_mcp/tools/unified/plan.py +876 -0
  138. foundry_mcp/tools/unified/pr.py +294 -0
  139. foundry_mcp/tools/unified/provider.py +589 -0
  140. foundry_mcp/tools/unified/research.py +1283 -0
  141. foundry_mcp/tools/unified/review.py +1042 -0
  142. foundry_mcp/tools/unified/review_helpers.py +314 -0
  143. foundry_mcp/tools/unified/router.py +102 -0
  144. foundry_mcp/tools/unified/server.py +565 -0
  145. foundry_mcp/tools/unified/spec.py +1283 -0
  146. foundry_mcp/tools/unified/task.py +3846 -0
  147. foundry_mcp/tools/unified/test.py +431 -0
  148. foundry_mcp/tools/unified/verification.py +520 -0
  149. foundry_mcp-0.8.22.dist-info/METADATA +344 -0
  150. foundry_mcp-0.8.22.dist-info/RECORD +153 -0
  151. foundry_mcp-0.8.22.dist-info/WHEEL +4 -0
  152. foundry_mcp-0.8.22.dist-info/entry_points.txt +3 -0
  153. foundry_mcp-0.8.22.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,89 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "Intake Item Schema",
4
+ "description": "Schema for bikelane intake items - fast work idea capture",
5
+ "type": "object",
6
+ "required": [
7
+ "schema_version",
8
+ "id",
9
+ "title",
10
+ "status",
11
+ "created_at",
12
+ "updated_at"
13
+ ],
14
+ "properties": {
15
+ "schema_version": {
16
+ "type": "string",
17
+ "const": "intake-v1",
18
+ "description": "Schema version identifier, fixed value 'intake-v1'"
19
+ },
20
+ "id": {
21
+ "type": "string",
22
+ "pattern": "^intake-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$",
23
+ "description": "Unique intake item identifier in format 'intake-<uuid4>'"
24
+ },
25
+ "title": {
26
+ "type": "string",
27
+ "minLength": 1,
28
+ "maxLength": 140,
29
+ "description": "Brief title for the intake item (1-140 characters)"
30
+ },
31
+ "description": {
32
+ "type": ["string", "null"],
33
+ "maxLength": 2000,
34
+ "description": "Detailed description of the work item (max 2000 characters)"
35
+ },
36
+ "status": {
37
+ "type": "string",
38
+ "enum": ["new", "dismissed"],
39
+ "description": "Item status: 'new' for triage queue, 'dismissed' for archived"
40
+ },
41
+ "priority": {
42
+ "type": "string",
43
+ "enum": ["p0", "p1", "p2", "p3", "p4"],
44
+ "default": "p2",
45
+ "description": "Priority level from p0 (highest) to p4 (lowest), defaults to p2"
46
+ },
47
+ "tags": {
48
+ "type": "array",
49
+ "items": {
50
+ "type": "string",
51
+ "minLength": 1,
52
+ "maxLength": 32,
53
+ "pattern": "^[a-z0-9_-]+$"
54
+ },
55
+ "maxItems": 20,
56
+ "uniqueItems": true,
57
+ "default": [],
58
+ "description": "Tags for categorization (max 20 items, each 1-32 chars, lowercase alphanumeric with _ and -)"
59
+ },
60
+ "source": {
61
+ "type": ["string", "null"],
62
+ "maxLength": 100,
63
+ "description": "Origin of the intake item (e.g., 'user-note', 'slack', 'email') max 100 chars"
64
+ },
65
+ "requester": {
66
+ "type": ["string", "null"],
67
+ "maxLength": 100,
68
+ "description": "Person or entity who requested the work (max 100 chars)"
69
+ },
70
+ "idempotency_key": {
71
+ "type": ["string", "null"],
72
+ "maxLength": 64,
73
+ "description": "Optional client-provided key for deduplication (max 64 chars)"
74
+ },
75
+ "created_at": {
76
+ "type": "string",
77
+ "format": "date-time",
78
+ "pattern": ".*Z$",
79
+ "description": "ISO 8601 UTC timestamp with Z suffix when item was created"
80
+ },
81
+ "updated_at": {
82
+ "type": "string",
83
+ "format": "date-time",
84
+ "pattern": ".*Z$",
85
+ "description": "ISO 8601 UTC timestamp with Z suffix of last update"
86
+ }
87
+ },
88
+ "additionalProperties": false
89
+ }
@@ -0,0 +1,414 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "SDD Spec File Schema",
4
+ "description": "Schema for SDD (Spec-Driven Development) JSON specification files",
5
+ "type": "object",
6
+ "required": [
7
+ "spec_id",
8
+ "generated",
9
+ "last_updated",
10
+ "hierarchy"
11
+ ],
12
+ "properties": {
13
+ "spec_id": {
14
+ "type": "string",
15
+ "pattern": "^[\\w-]+-\\d{4}-\\d{2}-\\d{2}-\\d{3}$",
16
+ "description": "Unique specification identifier: {feature}-{YYYY-MM-DD}-{nnn}"
17
+ },
18
+ "title": {
19
+ "type": "string",
20
+ "minLength": 1,
21
+ "description": "Human-readable specification title"
22
+ },
23
+ "generated": {
24
+ "type": "string",
25
+ "format": "date-time",
26
+ "description": "ISO 8601 timestamp when spec was generated"
27
+ },
28
+ "last_updated": {
29
+ "type": "string",
30
+ "format": "date-time",
31
+ "description": "ISO 8601 timestamp of last update"
32
+ },
33
+ "status": {
34
+ "type": "string",
35
+ "enum": ["pending", "in_progress", "completed", "blocked"],
36
+ "description": "Overall spec status (computed from task progress)"
37
+ },
38
+ "progress_percentage": {
39
+ "type": "integer",
40
+ "minimum": 0,
41
+ "maximum": 100,
42
+ "description": "Overall progress as percentage (0-100), computed from completed/total tasks"
43
+ },
44
+ "current_phase": {
45
+ "type": ["string", "null"],
46
+ "pattern": "^phase-\\d+(?:-[\\w-]+)*$",
47
+ "description": "ID of the currently active phase (first in_progress or first pending)"
48
+ },
49
+ "metadata": {
50
+ "type": "object",
51
+ "description": "Optional spec-level metadata",
52
+ "properties": {
53
+ "title": {
54
+ "type": "string",
55
+ "description": "Specification title retained for backward compatibility."
56
+ },
57
+ "description": {
58
+ "type": "string",
59
+ "description": "High-level description of the specification."
60
+ },
61
+ "mission": {
62
+ "type": "string",
63
+ "description": "Concise mission/goal statement for the entire specification."
64
+ },
65
+ "objectives": {
66
+ "type": "array",
67
+ "items": {
68
+ "type": "string"
69
+ },
70
+ "description": "Key objectives or acceptance criteria for the spec."
71
+ },
72
+ "complexity": {
73
+ "type": "string",
74
+ "description": "Relative complexity indicator."
75
+ },
76
+ "estimated_hours": {
77
+ "type": "number",
78
+ "minimum": 0
79
+ },
80
+ "owner": {
81
+ "type": "string"
82
+ },
83
+ "assumptions": {
84
+ "type": "array",
85
+ "items": {
86
+ "type": "string"
87
+ },
88
+ "description": "Design assumptions and constraints for this spec (e.g., single-user workflow, feature branch ownership)"
89
+ },
90
+ "revision_history": {
91
+ "type": "array",
92
+ "items": {
93
+ "type": "object",
94
+ "required": [
95
+ "version",
96
+ "date",
97
+ "changelog"
98
+ ],
99
+ "properties": {
100
+ "version": {
101
+ "type": "string",
102
+ "description": "Version number (e.g., 1.0, 1.1, 2.0)"
103
+ },
104
+ "date": {
105
+ "type": "string",
106
+ "format": "date-time",
107
+ "description": "ISO 8601 timestamp of revision"
108
+ },
109
+ "author": {
110
+ "type": "string",
111
+ "description": "Who made the revision"
112
+ },
113
+ "changelog": {
114
+ "type": "string",
115
+ "description": "Description of changes made in this revision"
116
+ },
117
+ "modified_by": {
118
+ "type": "string",
119
+ "description": "Tool or command that made the modification (e.g., sdd modify-spec)"
120
+ },
121
+ "review_triggered_by": {
122
+ "type": "string",
123
+ "description": "Path to review report that triggered this revision (if applicable)"
124
+ }
125
+ }
126
+ },
127
+ "description": "Version history tracking spec modifications over time"
128
+ }
129
+ },
130
+ "additionalProperties": true
131
+ },
132
+ "hierarchy": {
133
+ "type": "object",
134
+ "description": "Task hierarchy tree",
135
+ "patternProperties": {
136
+ "^spec-root$": {
137
+ "$ref": "#/definitions/node"
138
+ },
139
+ "^phase-\\d+(?:-[\\w-]+)*$": {
140
+ "$ref": "#/definitions/node"
141
+ },
142
+ "^task-\\d+(?:-\\d+)+$": {
143
+ "$ref": "#/definitions/node"
144
+ },
145
+ "^verify-\\d+(?:-\\d+)+$": {
146
+ "$ref": "#/definitions/node"
147
+ }
148
+ }
149
+ }
150
+ },
151
+ "definitions": {
152
+ "node": {
153
+ "type": "object",
154
+ "required": [
155
+ "type",
156
+ "title",
157
+ "status",
158
+ "parent",
159
+ "children",
160
+ "total_tasks",
161
+ "completed_tasks",
162
+ "metadata"
163
+ ],
164
+ "properties": {
165
+ "id": {
166
+ "type": "string",
167
+ "description": "Node identifier matching the key in hierarchy"
168
+ },
169
+ "type": {
170
+ "type": "string",
171
+ "enum": [
172
+ "spec",
173
+ "phase",
174
+ "group",
175
+ "task",
176
+ "subtask",
177
+ "verify"
178
+ ],
179
+ "description": "Node type in hierarchy"
180
+ },
181
+ "title": {
182
+ "type": "string",
183
+ "minLength": 1,
184
+ "description": "Human-readable title"
185
+ },
186
+ "status": {
187
+ "type": "string",
188
+ "enum": [
189
+ "pending",
190
+ "in_progress",
191
+ "completed",
192
+ "blocked"
193
+ ],
194
+ "description": "Current status"
195
+ },
196
+ "parent": {
197
+ "type": [
198
+ "string",
199
+ "null"
200
+ ],
201
+ "description": "Parent node ID (null only for spec-root)"
202
+ },
203
+ "children": {
204
+ "type": "array",
205
+ "items": {
206
+ "type": "string"
207
+ },
208
+ "description": "Array of child node IDs"
209
+ },
210
+ "metadata": {
211
+ "type": "object",
212
+ "description": "Node-specific metadata",
213
+ "default": {},
214
+ "properties": {
215
+ "purpose": {
216
+ "type": "string",
217
+ "description": "High-level intent or goal for the node's work."
218
+ },
219
+ "risk_level": {
220
+ "type": "string",
221
+ "description": "Qualitative risk indicator (e.g., low, medium, high)."
222
+ },
223
+ "estimated_hours": {
224
+ "type": "number",
225
+ "minimum": 0
226
+ },
227
+ "complexity": {
228
+ "type": "string",
229
+ "description": "Relative complexity label."
230
+ },
231
+ "task_category": {
232
+ "type": "string",
233
+ "enum": [
234
+ "investigation",
235
+ "implementation",
236
+ "refactoring",
237
+ "decision",
238
+ "research"
239
+ ],
240
+ "description": "Category of task work."
241
+ },
242
+ "file_path": {
243
+ "type": "string",
244
+ "description": "Primary file impacted by the node."
245
+ },
246
+ "description": {
247
+ "type": "string",
248
+ "description": "Task or node description."
249
+ },
250
+ "acceptance_criteria": {
251
+ "type": "array",
252
+ "items": {
253
+ "type": "string"
254
+ },
255
+ "description": "Acceptance criteria for the node."
256
+ },
257
+ "details": {
258
+ "oneOf": [
259
+ {"type": "string"},
260
+ {
261
+ "type": "array",
262
+ "items": {"type": "string"}
263
+ }
264
+ ],
265
+ "description": "Free-form detail text for subtasks and tasks. Can be a string or array of strings."
266
+ },
267
+ "changes": {
268
+ "type": "string",
269
+ "description": "Summary of expected code or documentation changes."
270
+ },
271
+ "reasoning": {
272
+ "type": "string",
273
+ "description": "Supporting rationale or justification."
274
+ },
275
+ "owner": {
276
+ "type": "string",
277
+ "description": "Optional owner or assignee."
278
+ },
279
+ "verification_type": {
280
+ "type": "string",
281
+ "enum": [
282
+ "run-tests",
283
+ "fidelity",
284
+ "manual"
285
+ ]
286
+ },
287
+ "agent": {
288
+ "type": "string",
289
+ "description": "Automation agent to run for verification."
290
+ },
291
+ "mcp_tool": {
292
+ "type": "string",
293
+ "description": "MCP tool to invoke for verification (e.g., mcp__foundry-mcp__spec-review-fidelity)."
294
+ },
295
+ "command": {
296
+ "type": "string",
297
+ "description": "Command or instructions for automated verification."
298
+ },
299
+ "expected": {
300
+ "type": "string",
301
+ "description": "Expected outcome of verification."
302
+ },
303
+ "scope": {
304
+ "type": "string",
305
+ "description": "Scope identifier for fidelity verification."
306
+ },
307
+ "target": {
308
+ "type": "string",
309
+ "description": "Target identifier for verification scope."
310
+ },
311
+ "status": {
312
+ "type": "string",
313
+ "description": "Optional workflow status for metadata (distinct from node status)."
314
+ },
315
+ "started_at": {
316
+ "type": "string",
317
+ "format": "date-time",
318
+ "description": "ISO 8601 timestamp when work started."
319
+ },
320
+ "completed_at": {
321
+ "type": "string",
322
+ "format": "date-time",
323
+ "description": "ISO 8601 timestamp when work completed."
324
+ },
325
+ "actual_hours": {
326
+ "type": "number",
327
+ "minimum": 0,
328
+ "description": "Actual hours spent on the node."
329
+ },
330
+ "on_failure": {
331
+ "$ref": "#/definitions/on_failure_actions"
332
+ }
333
+ },
334
+ "additionalProperties": true
335
+ },
336
+ "total_tasks": {
337
+ "type": "integer",
338
+ "minimum": 0,
339
+ "description": "Total tasks in this subtree"
340
+ },
341
+ "completed_tasks": {
342
+ "type": "integer",
343
+ "minimum": 0,
344
+ "description": "Completed tasks in this subtree"
345
+ },
346
+ "dependencies": {
347
+ "type": "object",
348
+ "properties": {
349
+ "blocked_by": {
350
+ "type": "array",
351
+ "items": {
352
+ "type": "string"
353
+ }
354
+ },
355
+ "depends": {
356
+ "type": "array",
357
+ "items": {
358
+ "type": "string"
359
+ }
360
+ },
361
+ "blocks": {
362
+ "type": "array",
363
+ "items": {
364
+ "type": "string"
365
+ }
366
+ }
367
+ }
368
+ }
369
+ }
370
+ },
371
+ "on_failure_actions": {
372
+ "type": "object",
373
+ "description": "Configurable actions to take when verification fails",
374
+ "properties": {
375
+ "consult": {
376
+ "type": "boolean",
377
+ "description": "Whether to trigger AI consultation for debugging (default: false)",
378
+ "default": false
379
+ },
380
+ "revert_status": {
381
+ "type": "string",
382
+ "enum": [
383
+ "pending",
384
+ "in_progress",
385
+ "blocked"
386
+ ],
387
+ "description": "Status to revert the parent task to on failure (default: in_progress)",
388
+ "default": "in_progress"
389
+ },
390
+ "max_retries": {
391
+ "type": "integer",
392
+ "minimum": 0,
393
+ "maximum": 5,
394
+ "description": "Maximum number of automatic retry attempts (default: 0)",
395
+ "default": 0
396
+ },
397
+ "notify": {
398
+ "type": "string",
399
+ "enum": [
400
+ "log"
401
+ ],
402
+ "description": "Notification method on failure (default: log)",
403
+ "default": "log"
404
+ },
405
+ "continue_on_failure": {
406
+ "type": "boolean",
407
+ "description": "Whether to continue with other verifications if this one fails (default: false)",
408
+ "default": false
409
+ }
410
+ },
411
+ "additionalProperties": false
412
+ }
413
+ }
414
+ }
foundry_mcp/server.py ADDED
@@ -0,0 +1,150 @@
1
+ """FastMCP server for foundry-mcp.
2
+
3
+ This server exposes the unified 17-router tool surface described in
4
+ `mcp/capabilities_manifest.json`.
5
+
6
+ Note: Legacy per-tool-name MCP endpoints are intentionally not registered.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import logging
12
+ import os
13
+ import sys
14
+ from typing import Optional
15
+
16
+ from mcp.server.fastmcp import FastMCP
17
+
18
+ from foundry_mcp.config import ServerConfig, get_config
19
+ from foundry_mcp.core.observability import audit_log, get_observability_manager
20
+ from foundry_mcp.resources.specs import register_spec_resources
21
+ from foundry_mcp.prompts.workflows import register_workflow_prompts
22
+ from foundry_mcp.tools.unified import register_unified_tools
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ def _init_observability(config: ServerConfig) -> None:
28
+ """Initialize the observability stack from server configuration."""
29
+
30
+ obs_config = config.observability
31
+ if not obs_config.enabled:
32
+ logger.debug("Observability disabled in configuration")
33
+ return
34
+
35
+ manager = get_observability_manager()
36
+ manager.initialize(obs_config)
37
+
38
+ tracing_status = "enabled" if manager.is_tracing_enabled() else "disabled"
39
+ metrics_status = "enabled" if manager.is_metrics_enabled() else "disabled"
40
+ logger.info(
41
+ "Observability initialized: tracing=%s, metrics=%s",
42
+ tracing_status,
43
+ metrics_status,
44
+ )
45
+
46
+
47
+ def _init_error_collection(config: ServerConfig) -> None:
48
+ """Initialize the error collection infrastructure."""
49
+
50
+ err_config = config.error_collection
51
+ if not err_config.enabled:
52
+ logger.debug("Error collection disabled in configuration")
53
+ return
54
+
55
+ try:
56
+ from foundry_mcp.core.error_collection import get_error_collector
57
+ from foundry_mcp.core.error_store import get_error_store
58
+
59
+ storage_path = err_config.get_storage_path()
60
+ store = get_error_store(storage_path)
61
+ collector = get_error_collector()
62
+ collector.initialize(store, err_config)
63
+ logger.info("Error collection initialized: storage_path=%s", storage_path)
64
+ except Exception as exc:
65
+ # Don't fail server startup due to optional error collection
66
+ logger.warning("Failed to initialize error collection: %s", exc)
67
+
68
+
69
+ def _init_metrics_persistence(config: ServerConfig) -> None:
70
+ """Initialize the metrics persistence infrastructure."""
71
+
72
+ metrics_config = config.metrics_persistence
73
+ if not metrics_config.enabled:
74
+ logger.debug("Metrics persistence disabled in configuration")
75
+ return
76
+
77
+ try:
78
+ from foundry_mcp.core.metrics_persistence import initialize_metrics_persistence
79
+ from foundry_mcp.core.metrics_store import get_metrics_store
80
+
81
+ collector = initialize_metrics_persistence(metrics_config)
82
+ if collector is None:
83
+ return
84
+
85
+ storage_path = metrics_config.get_storage_path()
86
+ store = get_metrics_store(storage_path)
87
+ deleted_count = store.cleanup(
88
+ retention_days=metrics_config.retention_days,
89
+ max_records=metrics_config.max_records,
90
+ )
91
+
92
+ if deleted_count > 0:
93
+ logger.info("Metrics cleanup: removed %s old records", deleted_count)
94
+
95
+ logger.info("Metrics persistence initialized: storage_path=%s", storage_path)
96
+ except Exception as exc:
97
+ # Don't fail server startup due to optional persistence
98
+ logger.warning("Failed to initialize metrics persistence: %s", exc)
99
+
100
+
101
+ def create_server(config: Optional[ServerConfig] = None) -> FastMCP:
102
+ """Create and configure the FastMCP server instance."""
103
+
104
+ if config is None:
105
+ config = get_config()
106
+
107
+ config.setup_logging()
108
+
109
+ _init_observability(config)
110
+ _init_error_collection(config)
111
+ _init_metrics_persistence(config)
112
+
113
+ mcp = FastMCP(name=config.server_name)
114
+
115
+ # Unified-only tool surface
116
+ register_unified_tools(mcp, config)
117
+
118
+ # Resources and prompts
119
+ register_spec_resources(mcp, config)
120
+ register_workflow_prompts(mcp, config)
121
+
122
+ logger.info("Server created: %s v%s", config.server_name, config.server_version)
123
+ return mcp
124
+
125
+
126
+ def main() -> None:
127
+ """Main entry point for the foundry-mcp server."""
128
+
129
+ try:
130
+ config = get_config()
131
+ server = create_server(config)
132
+
133
+ logger.info("Starting %s v%s", config.server_name, config.server_version)
134
+ audit_log("tool_invocation", tool="server_start", version=config.server_version)
135
+
136
+ server.run()
137
+
138
+ except KeyboardInterrupt:
139
+ logger.info("Server shutdown requested")
140
+ get_observability_manager().shutdown()
141
+ sys.exit(0)
142
+ except BaseException as exc:
143
+ logger.error("Server error: %s: %s", type(exc).__name__, exc)
144
+ audit_log("tool_invocation", tool="server_error", error=str(exc), success=False)
145
+ get_observability_manager().shutdown()
146
+ sys.exit(1)
147
+
148
+
149
+ if __name__ == "__main__":
150
+ main()
@@ -0,0 +1,10 @@
1
+ """MCP tool registration surface.
2
+
3
+ Only the unified 17-router tool surface is exported.
4
+ """
5
+
6
+ from foundry_mcp.tools.unified import register_unified_tools
7
+
8
+ __all__ = [
9
+ "register_unified_tools",
10
+ ]