omnibase_infra 0.2.1__py3-none-any.whl → 0.2.2__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.
- omnibase_infra/__init__.py +1 -1
- omnibase_infra/adapters/adapter_onex_tool_execution.py +446 -0
- omnibase_infra/cli/commands.py +1 -1
- omnibase_infra/configs/widget_mapping.yaml +176 -0
- omnibase_infra/contracts/handlers/filesystem/handler_contract.yaml +4 -1
- omnibase_infra/contracts/handlers/mcp/handler_contract.yaml +4 -1
- omnibase_infra/errors/error_compute_registry.py +4 -1
- omnibase_infra/errors/error_event_bus_registry.py +4 -1
- omnibase_infra/errors/error_infra.py +3 -1
- omnibase_infra/errors/error_policy_registry.py +4 -1
- omnibase_infra/handlers/handler_db.py +2 -1
- omnibase_infra/handlers/handler_graph.py +10 -5
- omnibase_infra/handlers/handler_mcp.py +736 -63
- omnibase_infra/handlers/mixins/mixin_consul_kv.py +4 -3
- omnibase_infra/handlers/mixins/mixin_consul_service.py +2 -1
- omnibase_infra/handlers/service_discovery/handler_service_discovery_consul.py +301 -4
- omnibase_infra/handlers/service_discovery/models/model_service_info.py +10 -0
- omnibase_infra/mixins/mixin_async_circuit_breaker.py +3 -2
- omnibase_infra/mixins/mixin_node_introspection.py +24 -7
- omnibase_infra/mixins/mixin_retry_execution.py +1 -1
- omnibase_infra/models/handlers/__init__.py +10 -0
- omnibase_infra/models/handlers/model_bootstrap_handler_descriptor.py +162 -0
- omnibase_infra/models/handlers/model_handler_descriptor.py +15 -0
- omnibase_infra/models/mcp/__init__.py +15 -0
- omnibase_infra/models/mcp/model_mcp_contract_config.py +80 -0
- omnibase_infra/models/mcp/model_mcp_server_config.py +67 -0
- omnibase_infra/models/mcp/model_mcp_tool_definition.py +73 -0
- omnibase_infra/models/mcp/model_mcp_tool_parameter.py +35 -0
- omnibase_infra/models/registration/model_node_capabilities.py +11 -0
- omnibase_infra/nodes/architecture_validator/contract_architecture_validator.yaml +0 -5
- omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py +17 -10
- omnibase_infra/nodes/effects/contract.yaml +0 -5
- omnibase_infra/nodes/node_registration_orchestrator/contract.yaml +7 -0
- omnibase_infra/nodes/node_registration_orchestrator/handlers/handler_node_introspected.py +86 -1
- omnibase_infra/nodes/node_registration_orchestrator/introspection_event_router.py +3 -3
- omnibase_infra/nodes/node_registration_orchestrator/registry/registry_infra_node_registration_orchestrator.py +9 -8
- omnibase_infra/nodes/node_registration_orchestrator/wiring.py +14 -13
- omnibase_infra/nodes/node_registration_storage_effect/contract.yaml +0 -5
- omnibase_infra/nodes/node_registration_storage_effect/registry/registry_infra_registration_storage.py +46 -25
- omnibase_infra/nodes/node_registry_effect/contract.yaml +0 -5
- omnibase_infra/nodes/node_registry_effect/handlers/handler_partial_retry.py +2 -1
- omnibase_infra/nodes/node_service_discovery_effect/registry/registry_infra_service_discovery.py +24 -19
- omnibase_infra/plugins/examples/plugin_json_normalizer.py +2 -2
- omnibase_infra/plugins/examples/plugin_json_normalizer_error_handling.py +2 -2
- omnibase_infra/plugins/plugin_compute_base.py +16 -2
- omnibase_infra/protocols/protocol_event_projector.py +1 -1
- omnibase_infra/runtime/__init__.py +51 -1
- omnibase_infra/runtime/binding_config_resolver.py +102 -37
- omnibase_infra/runtime/constants_notification.py +75 -0
- omnibase_infra/runtime/contract_handler_discovery.py +6 -1
- omnibase_infra/runtime/handler_bootstrap_source.py +514 -0
- omnibase_infra/runtime/handler_contract_config_loader.py +603 -0
- omnibase_infra/runtime/handler_contract_source.py +289 -167
- omnibase_infra/runtime/handler_plugin_loader.py +4 -2
- omnibase_infra/runtime/mixin_semver_cache.py +25 -1
- omnibase_infra/runtime/mixins/__init__.py +7 -0
- omnibase_infra/runtime/mixins/mixin_projector_notification_publishing.py +566 -0
- omnibase_infra/runtime/mixins/mixin_projector_sql_operations.py +31 -10
- omnibase_infra/runtime/models/__init__.py +24 -0
- omnibase_infra/runtime/models/model_health_check_result.py +2 -1
- omnibase_infra/runtime/models/model_projector_notification_config.py +171 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_config.py +112 -0
- omnibase_infra/runtime/models/model_transition_notification_outbox_metrics.py +140 -0
- omnibase_infra/runtime/models/model_transition_notification_publisher_metrics.py +357 -0
- omnibase_infra/runtime/projector_plugin_loader.py +1 -1
- omnibase_infra/runtime/projector_shell.py +229 -1
- omnibase_infra/runtime/protocols/__init__.py +10 -0
- omnibase_infra/runtime/registry/registry_protocol_binding.py +3 -2
- omnibase_infra/runtime/registry_policy.py +9 -326
- omnibase_infra/runtime/secret_resolver.py +4 -2
- omnibase_infra/runtime/service_kernel.py +10 -2
- omnibase_infra/runtime/service_message_dispatch_engine.py +4 -2
- omnibase_infra/runtime/service_runtime_host_process.py +225 -15
- omnibase_infra/runtime/transition_notification_outbox.py +1190 -0
- omnibase_infra/runtime/transition_notification_publisher.py +764 -0
- omnibase_infra/runtime/util_container_wiring.py +6 -5
- omnibase_infra/runtime/util_wiring.py +5 -1
- omnibase_infra/schemas/schema_transition_notification_outbox.sql +245 -0
- omnibase_infra/services/mcp/__init__.py +31 -0
- omnibase_infra/services/mcp/mcp_server_lifecycle.py +443 -0
- omnibase_infra/services/mcp/service_mcp_tool_discovery.py +411 -0
- omnibase_infra/services/mcp/service_mcp_tool_registry.py +329 -0
- omnibase_infra/services/mcp/service_mcp_tool_sync.py +547 -0
- omnibase_infra/services/registry_api/__init__.py +40 -0
- omnibase_infra/services/registry_api/main.py +243 -0
- omnibase_infra/services/registry_api/models/__init__.py +66 -0
- omnibase_infra/services/registry_api/models/model_capability_widget_mapping.py +38 -0
- omnibase_infra/services/registry_api/models/model_pagination_info.py +48 -0
- omnibase_infra/services/registry_api/models/model_registry_discovery_response.py +73 -0
- omnibase_infra/services/registry_api/models/model_registry_health_response.py +49 -0
- omnibase_infra/services/registry_api/models/model_registry_instance_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_node_view.py +88 -0
- omnibase_infra/services/registry_api/models/model_registry_summary.py +60 -0
- omnibase_infra/services/registry_api/models/model_response_list_instances.py +43 -0
- omnibase_infra/services/registry_api/models/model_response_list_nodes.py +51 -0
- omnibase_infra/services/registry_api/models/model_warning.py +49 -0
- omnibase_infra/services/registry_api/models/model_widget_defaults.py +28 -0
- omnibase_infra/services/registry_api/models/model_widget_mapping.py +51 -0
- omnibase_infra/services/registry_api/routes.py +371 -0
- omnibase_infra/services/registry_api/service.py +846 -0
- omnibase_infra/services/service_capability_query.py +4 -4
- omnibase_infra/services/service_health.py +3 -2
- omnibase_infra/services/service_timeout_emitter.py +13 -2
- omnibase_infra/utils/util_dsn_validation.py +1 -1
- omnibase_infra/validation/__init__.py +3 -19
- omnibase_infra/validation/contracts/security.validation.yaml +114 -0
- omnibase_infra/validation/infra_validators.py +35 -24
- omnibase_infra/validation/validation_exemptions.yaml +113 -9
- omnibase_infra/validation/validator_chain_propagation.py +2 -2
- omnibase_infra/validation/validator_runtime_shape.py +1 -1
- omnibase_infra/validation/validator_security.py +473 -370
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/METADATA +2 -2
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/RECORD +116 -74
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/WHEEL +0 -0
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/entry_points.txt +0 -0
- {omnibase_infra-0.2.1.dist-info → omnibase_infra-0.2.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""Bootstrap Handler Descriptor Model with Required handler_class.
|
|
4
|
+
|
|
5
|
+
This module provides ModelBootstrapHandlerDescriptor, a specialized handler
|
|
6
|
+
descriptor for bootstrap handlers that REQUIRES the handler_class field to be set.
|
|
7
|
+
|
|
8
|
+
Bootstrap handlers are hardcoded handlers that must always specify their
|
|
9
|
+
implementation class for dynamic import. Unlike contract-discovered handlers
|
|
10
|
+
where handler_class may be optional (inferred from convention), bootstrap
|
|
11
|
+
handlers have no contract file to derive the class from.
|
|
12
|
+
|
|
13
|
+
Part of OMN-1087: Implement HandlerBootstrapSource descriptor-based validation.
|
|
14
|
+
|
|
15
|
+
See Also:
|
|
16
|
+
- ModelHandlerDescriptor: Base descriptor with optional handler_class
|
|
17
|
+
- HandlerBootstrapSource: Source that uses this specialized descriptor
|
|
18
|
+
- BootstrapEffectDefinition: TypedDict for bootstrap handler definitions
|
|
19
|
+
|
|
20
|
+
.. versionadded:: 0.6.4
|
|
21
|
+
Created as part of OMN-1087 bootstrap handler validation.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from pydantic import ConfigDict, Field
|
|
27
|
+
|
|
28
|
+
from omnibase_infra.models.handlers.model_handler_descriptor import (
|
|
29
|
+
ModelHandlerDescriptor,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class ModelBootstrapHandlerDescriptor(ModelHandlerDescriptor):
|
|
34
|
+
"""Handler descriptor for bootstrap handlers with required handler_class.
|
|
35
|
+
|
|
36
|
+
This specialized descriptor extends ModelHandlerDescriptor to enforce that
|
|
37
|
+
handler_class is always set. Bootstrap handlers are hardcoded and must
|
|
38
|
+
specify their implementation class since there is no contract file to
|
|
39
|
+
derive the class from.
|
|
40
|
+
|
|
41
|
+
The key difference from ModelHandlerDescriptor:
|
|
42
|
+
- handler_class: Required (str) instead of optional (str | None)
|
|
43
|
+
|
|
44
|
+
All other fields maintain the same constraints as the parent class.
|
|
45
|
+
|
|
46
|
+
Attributes:
|
|
47
|
+
handler_id: Unique identifier for the handler (e.g., "bootstrap.consul").
|
|
48
|
+
name: Human-readable name for the handler.
|
|
49
|
+
version: Semantic version (ModelSemVer). Accepts string, dict, or ModelSemVer.
|
|
50
|
+
handler_kind: Handler kind (compute, effect, reducer, orchestrator).
|
|
51
|
+
input_model: Fully qualified input model class path.
|
|
52
|
+
output_model: Fully qualified output model class path.
|
|
53
|
+
description: Optional description of the handler.
|
|
54
|
+
handler_class: REQUIRED fully qualified Python class path for dynamic import.
|
|
55
|
+
contract_path: Path to the source contract file (typically None for bootstrap).
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
Create a bootstrap handler descriptor:
|
|
59
|
+
|
|
60
|
+
>>> descriptor = ModelBootstrapHandlerDescriptor(
|
|
61
|
+
... handler_id="bootstrap.consul",
|
|
62
|
+
... name="Consul Handler",
|
|
63
|
+
... version="1.0.0",
|
|
64
|
+
... handler_kind="effect",
|
|
65
|
+
... input_model="omnibase_infra.models.types.JsonDict",
|
|
66
|
+
... output_model="omnibase_core.models.dispatch.ModelHandlerOutput",
|
|
67
|
+
... handler_class="omnibase_infra.handlers.handler_consul.HandlerConsul",
|
|
68
|
+
... )
|
|
69
|
+
>>> descriptor.handler_class
|
|
70
|
+
'omnibase_infra.handlers.handler_consul.HandlerConsul'
|
|
71
|
+
|
|
72
|
+
Missing handler_class raises ValidationError:
|
|
73
|
+
|
|
74
|
+
>>> from pydantic import ValidationError
|
|
75
|
+
>>> try:
|
|
76
|
+
... ModelBootstrapHandlerDescriptor(
|
|
77
|
+
... handler_id="bootstrap.consul",
|
|
78
|
+
... name="Consul Handler",
|
|
79
|
+
... version="1.0.0",
|
|
80
|
+
... handler_kind="effect",
|
|
81
|
+
... input_model="omnibase_infra.models.types.JsonDict",
|
|
82
|
+
... output_model="omnibase_core.models.dispatch.ModelHandlerOutput",
|
|
83
|
+
... # handler_class omitted - will fail
|
|
84
|
+
... )
|
|
85
|
+
... except ValidationError as e:
|
|
86
|
+
... print("Validation failed as expected")
|
|
87
|
+
Validation failed as expected
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
ValidationError: If handler_class is not provided or is None.
|
|
91
|
+
|
|
92
|
+
.. versionadded:: 0.6.4
|
|
93
|
+
Created as part of OMN-1087 bootstrap handler validation.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
model_config = ConfigDict(
|
|
97
|
+
frozen=True,
|
|
98
|
+
extra="forbid",
|
|
99
|
+
strict=True,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Override handler_class to be required (no default, not optional)
|
|
103
|
+
# The Field() definition must include the pattern constraint from parent
|
|
104
|
+
handler_class: str = Field(
|
|
105
|
+
...,
|
|
106
|
+
min_length=3,
|
|
107
|
+
pattern=r"^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)+$",
|
|
108
|
+
description=(
|
|
109
|
+
"REQUIRED: Fully qualified Python class path for dynamic handler import. "
|
|
110
|
+
"Bootstrap handlers must always specify this field since they have no "
|
|
111
|
+
"contract file to derive the class from. "
|
|
112
|
+
"Example: 'omnibase_infra.handlers.handler_consul.HandlerConsul'"
|
|
113
|
+
),
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
def to_base_descriptor(self) -> ModelHandlerDescriptor:
|
|
117
|
+
"""Convert to base ModelHandlerDescriptor for API compatibility.
|
|
118
|
+
|
|
119
|
+
This method allows bootstrap descriptors to be used where the base
|
|
120
|
+
ModelHandlerDescriptor type is expected, while maintaining the
|
|
121
|
+
validation benefits of the bootstrap-specific model.
|
|
122
|
+
|
|
123
|
+
Implementation Notes:
|
|
124
|
+
Uses ``model_dump()`` without ``exclude_unset=True`` because:
|
|
125
|
+
|
|
126
|
+
1. **Field parity**: This child class has NO extra fields beyond the
|
|
127
|
+
parent. The only difference is ``handler_class`` type constraint
|
|
128
|
+
(required ``str`` vs optional ``str | None``).
|
|
129
|
+
|
|
130
|
+
2. **Type compatibility**: A ``str`` value from child is valid where
|
|
131
|
+
parent expects ``str | None``.
|
|
132
|
+
|
|
133
|
+
3. **Complete copy**: ``model_dump()`` ensures all fields are copied,
|
|
134
|
+
including those set to their default values.
|
|
135
|
+
|
|
136
|
+
Using ``exclude_unset=True`` would risk excluding fields that have
|
|
137
|
+
defaults but were explicitly set to those defaults during construction.
|
|
138
|
+
|
|
139
|
+
If future versions add child-specific fields not in parent, this
|
|
140
|
+
method MUST be updated to use ``exclude={'new_field'}`` or refactored.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
ModelHandlerDescriptor instance with all fields copied.
|
|
144
|
+
|
|
145
|
+
Example:
|
|
146
|
+
>>> bootstrap_desc = ModelBootstrapHandlerDescriptor(
|
|
147
|
+
... handler_id="bootstrap.consul",
|
|
148
|
+
... name="Consul Handler",
|
|
149
|
+
... version="1.0.0",
|
|
150
|
+
... handler_kind="effect",
|
|
151
|
+
... input_model="omnibase_infra.models.types.JsonDict",
|
|
152
|
+
... output_model="omnibase_core.models.dispatch.ModelHandlerOutput",
|
|
153
|
+
... handler_class="omnibase_infra.handlers.handler_consul.HandlerConsul",
|
|
154
|
+
... )
|
|
155
|
+
>>> base_desc = bootstrap_desc.to_base_descriptor()
|
|
156
|
+
>>> isinstance(base_desc, ModelHandlerDescriptor)
|
|
157
|
+
True
|
|
158
|
+
"""
|
|
159
|
+
return ModelHandlerDescriptor(**self.model_dump())
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
__all__ = ["ModelBootstrapHandlerDescriptor"]
|
|
@@ -99,6 +99,7 @@ class ModelHandlerDescriptor(BaseModel):
|
|
|
99
99
|
input_model: Fully qualified input model class path.
|
|
100
100
|
output_model: Fully qualified output model class path.
|
|
101
101
|
description: Optional description of the handler.
|
|
102
|
+
handler_class: Fully qualified Python class path for dynamic handler import.
|
|
102
103
|
contract_path: Path to the source contract file.
|
|
103
104
|
|
|
104
105
|
Example:
|
|
@@ -176,10 +177,24 @@ class ModelHandlerDescriptor(BaseModel):
|
|
|
176
177
|
default=None,
|
|
177
178
|
description="Optional description of the handler",
|
|
178
179
|
)
|
|
180
|
+
handler_class: str | None = Field(
|
|
181
|
+
default=None,
|
|
182
|
+
min_length=3,
|
|
183
|
+
pattern=r"^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)+$",
|
|
184
|
+
description="Fully qualified Python class path for dynamic handler import (e.g., 'omnibase_infra.handlers.handler_consul.HandlerConsul')",
|
|
185
|
+
)
|
|
179
186
|
contract_path: str | None = Field(
|
|
180
187
|
default=None,
|
|
181
188
|
description="Path to the source contract file",
|
|
182
189
|
)
|
|
190
|
+
contract_config: dict[str, JsonType] | None = Field(
|
|
191
|
+
default=None,
|
|
192
|
+
description=(
|
|
193
|
+
"Parsed configuration from the handler contract file. "
|
|
194
|
+
"Contains extracted values like security settings, tags, and handler metadata. "
|
|
195
|
+
"Populated during handler discovery when contract_path is set."
|
|
196
|
+
),
|
|
197
|
+
)
|
|
183
198
|
|
|
184
199
|
|
|
185
200
|
__all__ = ["LiteralHandlerKind", "ModelHandlerDescriptor"]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""MCP models for Model Context Protocol integration."""
|
|
4
|
+
|
|
5
|
+
from omnibase_infra.models.mcp.model_mcp_contract_config import ModelMCPContractConfig
|
|
6
|
+
from omnibase_infra.models.mcp.model_mcp_server_config import ModelMCPServerConfig
|
|
7
|
+
from omnibase_infra.models.mcp.model_mcp_tool_definition import ModelMCPToolDefinition
|
|
8
|
+
from omnibase_infra.models.mcp.model_mcp_tool_parameter import ModelMCPToolParameter
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"ModelMCPContractConfig",
|
|
12
|
+
"ModelMCPServerConfig",
|
|
13
|
+
"ModelMCPToolDefinition",
|
|
14
|
+
"ModelMCPToolParameter",
|
|
15
|
+
]
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""MCP contract configuration model for enabling nodes as MCP tools.
|
|
4
|
+
|
|
5
|
+
This model defines the `mcp` field that can be added to ONEX contracts to expose
|
|
6
|
+
orchestrator nodes as MCP tools for AI agent integration.
|
|
7
|
+
|
|
8
|
+
Example contract.yaml:
|
|
9
|
+
node_type: ORCHESTRATOR_GENERIC
|
|
10
|
+
mcp:
|
|
11
|
+
expose: true
|
|
12
|
+
tool_name: "workflow_execute"
|
|
13
|
+
description: "Execute a workflow"
|
|
14
|
+
timeout_seconds: 30
|
|
15
|
+
|
|
16
|
+
Enforcement Rule:
|
|
17
|
+
The `mcp.expose` field is ONLY valid for ORCHESTRATOR_GENERIC nodes.
|
|
18
|
+
Non-orchestrator nodes with `mcp.expose: true` will be ignored during
|
|
19
|
+
registration - the MCP tags will not be added to Consul.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
from pydantic import BaseModel, Field
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ModelMCPContractConfig(BaseModel):
|
|
28
|
+
"""MCP configuration for exposing a node as an MCP tool.
|
|
29
|
+
|
|
30
|
+
This configuration is embedded in a node's contract.yaml to enable
|
|
31
|
+
AI agents to discover and invoke the node as an MCP tool.
|
|
32
|
+
|
|
33
|
+
Attributes:
|
|
34
|
+
expose: Whether to expose this node as an MCP tool. When True and
|
|
35
|
+
the node is an orchestrator, it will be registered with Consul
|
|
36
|
+
using MCP-specific tags for tool discovery.
|
|
37
|
+
tool_name: Optional stable name for the MCP tool. If not provided,
|
|
38
|
+
defaults to the node's name. Use this to provide a consistent
|
|
39
|
+
tool name across node version changes.
|
|
40
|
+
description: Optional AI-friendly description of what this tool does.
|
|
41
|
+
If not provided, the node's description from the contract is used.
|
|
42
|
+
timeout_seconds: Optional execution timeout in seconds. Defaults to 30.
|
|
43
|
+
This is enforced when AI agents invoke the tool.
|
|
44
|
+
|
|
45
|
+
Example:
|
|
46
|
+
>>> config = ModelMCPContractConfig(
|
|
47
|
+
... expose=True,
|
|
48
|
+
... tool_name="my_workflow",
|
|
49
|
+
... description="Execute my custom workflow",
|
|
50
|
+
... timeout_seconds=60,
|
|
51
|
+
... )
|
|
52
|
+
>>> config.expose
|
|
53
|
+
True
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
expose: bool = Field(
|
|
57
|
+
default=False,
|
|
58
|
+
description="Whether to expose this node as an MCP tool. "
|
|
59
|
+
"Only valid for ORCHESTRATOR_GENERIC nodes.",
|
|
60
|
+
)
|
|
61
|
+
tool_name: str | None = Field(
|
|
62
|
+
default=None,
|
|
63
|
+
description="Optional stable name for the MCP tool. "
|
|
64
|
+
"Defaults to the node's name if not specified.",
|
|
65
|
+
)
|
|
66
|
+
description: str | None = Field(
|
|
67
|
+
default=None,
|
|
68
|
+
description="Optional AI-friendly description of what this tool does. "
|
|
69
|
+
"If not provided, the node's description from the contract is used.",
|
|
70
|
+
)
|
|
71
|
+
timeout_seconds: int = Field(
|
|
72
|
+
default=30,
|
|
73
|
+
ge=1,
|
|
74
|
+
le=300,
|
|
75
|
+
description="Execution timeout in seconds for tool invocations. "
|
|
76
|
+
"Minimum: 1, Maximum: 300 (5 minutes).",
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
__all__ = ["ModelMCPContractConfig"]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""MCP server configuration model.
|
|
4
|
+
|
|
5
|
+
This model defines the configuration for the MCP server lifecycle,
|
|
6
|
+
including Consul discovery, Kafka hot reload, and HTTP server settings.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel, Field
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ModelMCPServerConfig(BaseModel):
|
|
15
|
+
"""Configuration for the MCP server lifecycle.
|
|
16
|
+
|
|
17
|
+
This model captures all configuration needed for the MCP server:
|
|
18
|
+
- Consul connection settings for service discovery
|
|
19
|
+
- Kafka settings for hot reload
|
|
20
|
+
- HTTP server binding
|
|
21
|
+
- Execution defaults
|
|
22
|
+
|
|
23
|
+
Attributes:
|
|
24
|
+
consul_host: Consul server hostname for service discovery.
|
|
25
|
+
consul_port: Consul server port.
|
|
26
|
+
consul_scheme: HTTP scheme for Consul (http/https).
|
|
27
|
+
consul_token: Optional ACL token for Consul authentication.
|
|
28
|
+
kafka_enabled: Whether to enable Kafka for hot reload.
|
|
29
|
+
http_host: Host to bind the MCP HTTP server.
|
|
30
|
+
http_port: Port for the MCP HTTP server.
|
|
31
|
+
default_timeout: Default execution timeout for tools.
|
|
32
|
+
dev_mode: Whether to run in development mode (local contracts).
|
|
33
|
+
contracts_dir: Directory for contract scanning in dev mode.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
consul_host: str = Field(default="localhost", description="Consul server hostname")
|
|
37
|
+
consul_port: int = Field(
|
|
38
|
+
default=8500, ge=1, le=65535, description="Consul server port"
|
|
39
|
+
)
|
|
40
|
+
consul_scheme: str = Field(
|
|
41
|
+
default="http", pattern="^https?$", description="HTTP scheme for Consul"
|
|
42
|
+
)
|
|
43
|
+
consul_token: str | None = Field(
|
|
44
|
+
default=None, description="Optional ACL token for Consul authentication"
|
|
45
|
+
)
|
|
46
|
+
kafka_enabled: bool = Field(
|
|
47
|
+
default=True, description="Whether to enable Kafka for hot reload"
|
|
48
|
+
)
|
|
49
|
+
http_host: str = Field(
|
|
50
|
+
default="0.0.0.0", # noqa: S104 - Intentional bind-all for server
|
|
51
|
+
description="Host to bind the MCP HTTP server",
|
|
52
|
+
)
|
|
53
|
+
http_port: int = Field(
|
|
54
|
+
default=8090, ge=1, le=65535, description="Port for the MCP HTTP server"
|
|
55
|
+
)
|
|
56
|
+
default_timeout: float = Field(
|
|
57
|
+
default=30.0, gt=0, le=300, description="Default execution timeout for tools"
|
|
58
|
+
)
|
|
59
|
+
dev_mode: bool = Field(
|
|
60
|
+
default=False, description="Whether to run in development mode"
|
|
61
|
+
)
|
|
62
|
+
contracts_dir: str | None = Field(
|
|
63
|
+
default=None, description="Directory for contract scanning in dev mode"
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
__all__ = ["ModelMCPServerConfig"]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""MCP tool definition model for representing ONEX nodes as MCP tools.
|
|
4
|
+
|
|
5
|
+
This model is used by the MCP adapter layer to:
|
|
6
|
+
1. Cache discovered tools in the registry
|
|
7
|
+
2. Generate MCP tool schemas for AI agents
|
|
8
|
+
3. Route tool invocations to ONEX orchestrators
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel, Field
|
|
14
|
+
|
|
15
|
+
from omnibase_infra.models.mcp.model_mcp_tool_parameter import ModelMCPToolParameter
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ModelMCPToolDefinition(BaseModel):
|
|
19
|
+
"""Complete MCP tool definition derived from an ONEX orchestrator node.
|
|
20
|
+
|
|
21
|
+
This model captures all information needed to:
|
|
22
|
+
- Expose the tool to AI agents via MCP protocol
|
|
23
|
+
- Route invocations to the correct ONEX orchestrator
|
|
24
|
+
- Enforce execution constraints (timeout, etc.)
|
|
25
|
+
|
|
26
|
+
Attributes:
|
|
27
|
+
name: Stable tool name for AI agent invocation. This is derived from
|
|
28
|
+
contract.mcp.tool_name or falls back to the node name.
|
|
29
|
+
description: AI-friendly description of tool functionality.
|
|
30
|
+
version: Tool version from the node contract.
|
|
31
|
+
parameters: List of input parameters with type information.
|
|
32
|
+
input_schema: JSON Schema for input validation.
|
|
33
|
+
orchestrator_node_id: UUID of the ONEX orchestrator node.
|
|
34
|
+
orchestrator_service_id: Consul service ID for routing.
|
|
35
|
+
endpoint: HTTP endpoint for direct invocation (if available).
|
|
36
|
+
timeout_seconds: Execution timeout for tool invocations.
|
|
37
|
+
metadata: Additional metadata for routing and observability.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
name: str = Field(description="Stable tool name for MCP invocation")
|
|
41
|
+
description: str = Field(description="AI-friendly tool description")
|
|
42
|
+
version: str = Field(default="1.0.0", description="Tool version")
|
|
43
|
+
parameters: list[ModelMCPToolParameter] = Field(
|
|
44
|
+
default_factory=list, description="Input parameters"
|
|
45
|
+
)
|
|
46
|
+
input_schema: dict[str, object] = Field(
|
|
47
|
+
default_factory=lambda: dict[str, object]({"type": "object", "properties": {}}),
|
|
48
|
+
description="JSON Schema for input validation",
|
|
49
|
+
)
|
|
50
|
+
orchestrator_node_id: str | None = Field(
|
|
51
|
+
default=None, description="UUID of the source orchestrator node"
|
|
52
|
+
)
|
|
53
|
+
orchestrator_service_id: str | None = Field(
|
|
54
|
+
default=None, description="Consul service ID for routing"
|
|
55
|
+
)
|
|
56
|
+
endpoint: str | None = Field(
|
|
57
|
+
default=None, description="HTTP endpoint for direct invocation"
|
|
58
|
+
)
|
|
59
|
+
timeout_seconds: int = Field(
|
|
60
|
+
default=30, ge=1, le=300, description="Execution timeout in seconds"
|
|
61
|
+
)
|
|
62
|
+
metadata: dict[str, object] = Field(
|
|
63
|
+
default_factory=dict,
|
|
64
|
+
description="Additional metadata (tags, input_model module, etc.)",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def tool_type(self) -> str:
|
|
69
|
+
"""Return the MCP tool type. Always 'function' for ONEX nodes."""
|
|
70
|
+
return "function"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
__all__ = ["ModelMCPToolDefinition"]
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2025 OmniNode Team
|
|
3
|
+
"""MCP tool parameter model for representing tool input parameters."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ModelMCPToolParameter(BaseModel):
|
|
11
|
+
"""Parameter definition for an MCP tool.
|
|
12
|
+
|
|
13
|
+
Represents a single parameter that can be passed to an MCP tool,
|
|
14
|
+
including its type, validation constraints, and documentation.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
name: str = Field(description="Parameter name")
|
|
18
|
+
parameter_type: str = Field(
|
|
19
|
+
default="string",
|
|
20
|
+
description="JSON Schema type: string, number, boolean, array, object",
|
|
21
|
+
)
|
|
22
|
+
description: str = Field(default="", description="Human-readable description")
|
|
23
|
+
required: bool = Field(
|
|
24
|
+
default=True, description="Whether this parameter is required"
|
|
25
|
+
)
|
|
26
|
+
default_value: object | None = Field(
|
|
27
|
+
default=None, description="Default value if not provided"
|
|
28
|
+
)
|
|
29
|
+
json_schema: dict[str, object] | None = Field(
|
|
30
|
+
default=None,
|
|
31
|
+
description="Additional JSON Schema constraints (enum, format, etc.)",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
__all__ = ["ModelMCPToolParameter"]
|
|
@@ -12,9 +12,12 @@ Note:
|
|
|
12
12
|
would not correctly handle this distinction.
|
|
13
13
|
"""
|
|
14
14
|
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
15
17
|
from pydantic import BaseModel, ConfigDict, Field
|
|
16
18
|
|
|
17
19
|
from omnibase_core.types import JsonType
|
|
20
|
+
from omnibase_infra.models.mcp.model_mcp_contract_config import ModelMCPContractConfig
|
|
18
21
|
|
|
19
22
|
|
|
20
23
|
class ModelNodeCapabilities(BaseModel):
|
|
@@ -94,6 +97,14 @@ class ModelNodeCapabilities(BaseModel):
|
|
|
94
97
|
description="Nested configuration (JSON-serializable values)",
|
|
95
98
|
)
|
|
96
99
|
|
|
100
|
+
# MCP configuration for exposing node as AI agent tool
|
|
101
|
+
# Only valid for ORCHESTRATOR nodes - ignored for other node types
|
|
102
|
+
mcp: ModelMCPContractConfig | None = Field(
|
|
103
|
+
default=None,
|
|
104
|
+
description="MCP configuration for exposing node as AI agent tool. "
|
|
105
|
+
"Only valid for ORCHESTRATOR_GENERIC nodes.",
|
|
106
|
+
)
|
|
107
|
+
|
|
97
108
|
def __getitem__(self, key: str) -> object:
|
|
98
109
|
"""Enable dict-like access to capabilities.
|
|
99
110
|
|
omnibase_infra/nodes/architecture_validator/registry/registry_infra_architecture_validator.py
CHANGED
|
@@ -39,7 +39,7 @@ class RegistryInfraArchitectureValidator:
|
|
|
39
39
|
|
|
40
40
|
This registry provides a static method to register the NodeArchitectureValidator
|
|
41
41
|
with the ONEX dependency injection container. The validator is registered as
|
|
42
|
-
|
|
42
|
+
an instance after being created with the container reference.
|
|
43
43
|
|
|
44
44
|
Thread Safety:
|
|
45
45
|
Registration is typically done at startup before the container is frozen.
|
|
@@ -53,17 +53,17 @@ class RegistryInfraArchitectureValidator:
|
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
container = ModelONEXContainer()
|
|
56
|
-
RegistryInfraArchitectureValidator.register(container)
|
|
56
|
+
await RegistryInfraArchitectureValidator.register(container)
|
|
57
57
|
```
|
|
58
58
|
"""
|
|
59
59
|
|
|
60
60
|
@staticmethod
|
|
61
|
-
def register(container: ModelONEXContainer) -> None:
|
|
61
|
+
async def register(container: ModelONEXContainer) -> None:
|
|
62
62
|
"""Register architecture validator with container.
|
|
63
63
|
|
|
64
64
|
Registers the NodeArchitectureValidator as a service in the ONEX
|
|
65
|
-
dependency injection container. The validator is
|
|
66
|
-
|
|
65
|
+
dependency injection container. The validator is created immediately
|
|
66
|
+
and registered as a singleton instance.
|
|
67
67
|
|
|
68
68
|
Args:
|
|
69
69
|
container: The DI container to register with.
|
|
@@ -77,22 +77,29 @@ class RegistryInfraArchitectureValidator:
|
|
|
77
77
|
Example:
|
|
78
78
|
```python
|
|
79
79
|
container = ModelONEXContainer()
|
|
80
|
-
RegistryInfraArchitectureValidator.register(container)
|
|
80
|
+
await RegistryInfraArchitectureValidator.register(container)
|
|
81
81
|
|
|
82
82
|
# Resolve when needed
|
|
83
|
-
validator = container.
|
|
83
|
+
validator = await container.service_registry.resolve_service(
|
|
84
|
+
NodeArchitectureValidator
|
|
85
|
+
)
|
|
84
86
|
result = await validator.compute(request)
|
|
85
87
|
```
|
|
86
88
|
"""
|
|
89
|
+
from omnibase_core.enums import EnumInjectionScope
|
|
90
|
+
|
|
87
91
|
# Check if service_registry is available
|
|
88
92
|
if container.service_registry is None:
|
|
89
93
|
# Container doesn't have full DI support - skip registration
|
|
90
94
|
# This allows the code to work with minimal container configurations
|
|
91
95
|
return
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
# Create instance and register (factory registration not supported in v1.0)
|
|
98
|
+
validator_instance = NodeArchitectureValidator(container)
|
|
99
|
+
await container.service_registry.register_instance(
|
|
100
|
+
interface=NodeArchitectureValidator,
|
|
101
|
+
instance=validator_instance,
|
|
102
|
+
scope=EnumInjectionScope.GLOBAL,
|
|
96
103
|
)
|
|
97
104
|
|
|
98
105
|
|
|
@@ -36,6 +36,13 @@ node_version: "1.0.0"
|
|
|
36
36
|
name: "node_registration_orchestrator"
|
|
37
37
|
node_type: "ORCHESTRATOR_GENERIC"
|
|
38
38
|
description: "Registration workflow orchestrator that coordinates node lifecycle by calling reducer for intents and effect for execution."
|
|
39
|
+
# MCP (Model Context Protocol) Configuration
|
|
40
|
+
# Exposes this orchestrator as an AI-invocable tool via MCP server
|
|
41
|
+
mcp:
|
|
42
|
+
expose: true
|
|
43
|
+
tool_name: "register_node"
|
|
44
|
+
description: "Register a new ONEX node with the cluster. Handles Consul service registration and PostgreSQL metadata storage. Returns registration status and assigned service ID."
|
|
45
|
+
timeout_seconds: 30
|
|
39
46
|
input_model:
|
|
40
47
|
name: "ModelOrchestratorInput"
|
|
41
48
|
module: "omnibase_infra.nodes.node_registration_orchestrator.models"
|