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.
- foundry_mcp/__init__.py +13 -0
- foundry_mcp/cli/__init__.py +67 -0
- foundry_mcp/cli/__main__.py +9 -0
- foundry_mcp/cli/agent.py +96 -0
- foundry_mcp/cli/commands/__init__.py +37 -0
- foundry_mcp/cli/commands/cache.py +137 -0
- foundry_mcp/cli/commands/dashboard.py +148 -0
- foundry_mcp/cli/commands/dev.py +446 -0
- foundry_mcp/cli/commands/journal.py +377 -0
- foundry_mcp/cli/commands/lifecycle.py +274 -0
- foundry_mcp/cli/commands/modify.py +824 -0
- foundry_mcp/cli/commands/plan.py +640 -0
- foundry_mcp/cli/commands/pr.py +393 -0
- foundry_mcp/cli/commands/review.py +667 -0
- foundry_mcp/cli/commands/session.py +472 -0
- foundry_mcp/cli/commands/specs.py +686 -0
- foundry_mcp/cli/commands/tasks.py +807 -0
- foundry_mcp/cli/commands/testing.py +676 -0
- foundry_mcp/cli/commands/validate.py +982 -0
- foundry_mcp/cli/config.py +98 -0
- foundry_mcp/cli/context.py +298 -0
- foundry_mcp/cli/logging.py +212 -0
- foundry_mcp/cli/main.py +44 -0
- foundry_mcp/cli/output.py +122 -0
- foundry_mcp/cli/registry.py +110 -0
- foundry_mcp/cli/resilience.py +178 -0
- foundry_mcp/cli/transcript.py +217 -0
- foundry_mcp/config.py +1454 -0
- foundry_mcp/core/__init__.py +144 -0
- foundry_mcp/core/ai_consultation.py +1773 -0
- foundry_mcp/core/batch_operations.py +1202 -0
- foundry_mcp/core/cache.py +195 -0
- foundry_mcp/core/capabilities.py +446 -0
- foundry_mcp/core/concurrency.py +898 -0
- foundry_mcp/core/context.py +540 -0
- foundry_mcp/core/discovery.py +1603 -0
- foundry_mcp/core/error_collection.py +728 -0
- foundry_mcp/core/error_store.py +592 -0
- foundry_mcp/core/health.py +749 -0
- foundry_mcp/core/intake.py +933 -0
- foundry_mcp/core/journal.py +700 -0
- foundry_mcp/core/lifecycle.py +412 -0
- foundry_mcp/core/llm_config.py +1376 -0
- foundry_mcp/core/llm_patterns.py +510 -0
- foundry_mcp/core/llm_provider.py +1569 -0
- foundry_mcp/core/logging_config.py +374 -0
- foundry_mcp/core/metrics_persistence.py +584 -0
- foundry_mcp/core/metrics_registry.py +327 -0
- foundry_mcp/core/metrics_store.py +641 -0
- foundry_mcp/core/modifications.py +224 -0
- foundry_mcp/core/naming.py +146 -0
- foundry_mcp/core/observability.py +1216 -0
- foundry_mcp/core/otel.py +452 -0
- foundry_mcp/core/otel_stubs.py +264 -0
- foundry_mcp/core/pagination.py +255 -0
- foundry_mcp/core/progress.py +387 -0
- foundry_mcp/core/prometheus.py +564 -0
- foundry_mcp/core/prompts/__init__.py +464 -0
- foundry_mcp/core/prompts/fidelity_review.py +691 -0
- foundry_mcp/core/prompts/markdown_plan_review.py +515 -0
- foundry_mcp/core/prompts/plan_review.py +627 -0
- foundry_mcp/core/providers/__init__.py +237 -0
- foundry_mcp/core/providers/base.py +515 -0
- foundry_mcp/core/providers/claude.py +472 -0
- foundry_mcp/core/providers/codex.py +637 -0
- foundry_mcp/core/providers/cursor_agent.py +630 -0
- foundry_mcp/core/providers/detectors.py +515 -0
- foundry_mcp/core/providers/gemini.py +426 -0
- foundry_mcp/core/providers/opencode.py +718 -0
- foundry_mcp/core/providers/opencode_wrapper.js +308 -0
- foundry_mcp/core/providers/package-lock.json +24 -0
- foundry_mcp/core/providers/package.json +25 -0
- foundry_mcp/core/providers/registry.py +607 -0
- foundry_mcp/core/providers/test_provider.py +171 -0
- foundry_mcp/core/providers/validation.py +857 -0
- foundry_mcp/core/rate_limit.py +427 -0
- foundry_mcp/core/research/__init__.py +68 -0
- foundry_mcp/core/research/memory.py +528 -0
- foundry_mcp/core/research/models.py +1234 -0
- foundry_mcp/core/research/providers/__init__.py +40 -0
- foundry_mcp/core/research/providers/base.py +242 -0
- foundry_mcp/core/research/providers/google.py +507 -0
- foundry_mcp/core/research/providers/perplexity.py +442 -0
- foundry_mcp/core/research/providers/semantic_scholar.py +544 -0
- foundry_mcp/core/research/providers/tavily.py +383 -0
- foundry_mcp/core/research/workflows/__init__.py +25 -0
- foundry_mcp/core/research/workflows/base.py +298 -0
- foundry_mcp/core/research/workflows/chat.py +271 -0
- foundry_mcp/core/research/workflows/consensus.py +539 -0
- foundry_mcp/core/research/workflows/deep_research.py +4142 -0
- foundry_mcp/core/research/workflows/ideate.py +682 -0
- foundry_mcp/core/research/workflows/thinkdeep.py +405 -0
- foundry_mcp/core/resilience.py +600 -0
- foundry_mcp/core/responses.py +1624 -0
- foundry_mcp/core/review.py +366 -0
- foundry_mcp/core/security.py +438 -0
- foundry_mcp/core/spec.py +4119 -0
- foundry_mcp/core/task.py +2463 -0
- foundry_mcp/core/testing.py +839 -0
- foundry_mcp/core/validation.py +2357 -0
- foundry_mcp/dashboard/__init__.py +32 -0
- foundry_mcp/dashboard/app.py +119 -0
- foundry_mcp/dashboard/components/__init__.py +17 -0
- foundry_mcp/dashboard/components/cards.py +88 -0
- foundry_mcp/dashboard/components/charts.py +177 -0
- foundry_mcp/dashboard/components/filters.py +136 -0
- foundry_mcp/dashboard/components/tables.py +195 -0
- foundry_mcp/dashboard/data/__init__.py +11 -0
- foundry_mcp/dashboard/data/stores.py +433 -0
- foundry_mcp/dashboard/launcher.py +300 -0
- foundry_mcp/dashboard/views/__init__.py +12 -0
- foundry_mcp/dashboard/views/errors.py +217 -0
- foundry_mcp/dashboard/views/metrics.py +164 -0
- foundry_mcp/dashboard/views/overview.py +96 -0
- foundry_mcp/dashboard/views/providers.py +83 -0
- foundry_mcp/dashboard/views/sdd_workflow.py +255 -0
- foundry_mcp/dashboard/views/tool_usage.py +139 -0
- foundry_mcp/prompts/__init__.py +9 -0
- foundry_mcp/prompts/workflows.py +525 -0
- foundry_mcp/resources/__init__.py +9 -0
- foundry_mcp/resources/specs.py +591 -0
- foundry_mcp/schemas/__init__.py +38 -0
- foundry_mcp/schemas/intake-schema.json +89 -0
- foundry_mcp/schemas/sdd-spec-schema.json +414 -0
- foundry_mcp/server.py +150 -0
- foundry_mcp/tools/__init__.py +10 -0
- foundry_mcp/tools/unified/__init__.py +92 -0
- foundry_mcp/tools/unified/authoring.py +3620 -0
- foundry_mcp/tools/unified/context_helpers.py +98 -0
- foundry_mcp/tools/unified/documentation_helpers.py +268 -0
- foundry_mcp/tools/unified/environment.py +1341 -0
- foundry_mcp/tools/unified/error.py +479 -0
- foundry_mcp/tools/unified/health.py +225 -0
- foundry_mcp/tools/unified/journal.py +841 -0
- foundry_mcp/tools/unified/lifecycle.py +640 -0
- foundry_mcp/tools/unified/metrics.py +777 -0
- foundry_mcp/tools/unified/plan.py +876 -0
- foundry_mcp/tools/unified/pr.py +294 -0
- foundry_mcp/tools/unified/provider.py +589 -0
- foundry_mcp/tools/unified/research.py +1283 -0
- foundry_mcp/tools/unified/review.py +1042 -0
- foundry_mcp/tools/unified/review_helpers.py +314 -0
- foundry_mcp/tools/unified/router.py +102 -0
- foundry_mcp/tools/unified/server.py +565 -0
- foundry_mcp/tools/unified/spec.py +1283 -0
- foundry_mcp/tools/unified/task.py +3846 -0
- foundry_mcp/tools/unified/test.py +431 -0
- foundry_mcp/tools/unified/verification.py +520 -0
- foundry_mcp-0.8.22.dist-info/METADATA +344 -0
- foundry_mcp-0.8.22.dist-info/RECORD +153 -0
- foundry_mcp-0.8.22.dist-info/WHEEL +4 -0
- foundry_mcp-0.8.22.dist-info/entry_points.txt +3 -0
- 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()
|