flock-core 0.5.0b28__py3-none-any.whl → 0.5.56b0__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 flock-core might be problematic. Click here for more details.
- flock/__init__.py +12 -217
- flock/agent.py +678 -0
- flock/api/themes.py +71 -0
- flock/artifacts.py +79 -0
- flock/cli.py +75 -0
- flock/components.py +173 -0
- flock/dashboard/__init__.py +28 -0
- flock/dashboard/collector.py +283 -0
- flock/dashboard/events.py +182 -0
- flock/dashboard/launcher.py +230 -0
- flock/dashboard/service.py +537 -0
- flock/dashboard/websocket.py +235 -0
- flock/engines/__init__.py +6 -0
- flock/engines/dspy_engine.py +856 -0
- flock/examples.py +128 -0
- flock/{core/util → helper}/cli_helper.py +4 -3
- flock/{core/logging → logging}/__init__.py +2 -3
- flock/{core/logging → logging}/formatters/enum_builder.py +3 -4
- flock/{core/logging → logging}/formatters/theme_builder.py +19 -44
- flock/{core/logging → logging}/formatters/themed_formatter.py +69 -115
- flock/{core/logging → logging}/logging.py +77 -61
- flock/{core/logging → logging}/telemetry.py +20 -26
- flock/{core/logging → logging}/telemetry_exporter/base_exporter.py +2 -2
- flock/{core/logging → logging}/telemetry_exporter/file_exporter.py +6 -9
- flock/{core/logging → logging}/telemetry_exporter/sqlite_exporter.py +2 -3
- flock/{core/logging → logging}/trace_and_logged.py +20 -24
- flock/mcp/__init__.py +91 -0
- flock/{core/mcp/mcp_client.py → mcp/client.py} +103 -154
- flock/{core/mcp/mcp_config.py → mcp/config.py} +62 -117
- flock/mcp/manager.py +255 -0
- flock/mcp/servers/sse/__init__.py +1 -1
- flock/mcp/servers/sse/flock_sse_server.py +11 -53
- flock/mcp/servers/stdio/__init__.py +1 -1
- flock/mcp/servers/stdio/flock_stdio_server.py +8 -48
- flock/mcp/servers/streamable_http/flock_streamable_http_server.py +17 -62
- flock/mcp/servers/websockets/flock_websocket_server.py +7 -40
- flock/{core/mcp/flock_mcp_tool.py → mcp/tool.py} +16 -26
- flock/mcp/types/__init__.py +42 -0
- flock/{core/mcp → mcp}/types/callbacks.py +9 -15
- flock/{core/mcp → mcp}/types/factories.py +7 -6
- flock/{core/mcp → mcp}/types/handlers.py +13 -18
- flock/{core/mcp → mcp}/types/types.py +70 -74
- flock/{core/mcp → mcp}/util/helpers.py +1 -1
- flock/orchestrator.py +645 -0
- flock/registry.py +148 -0
- flock/runtime.py +262 -0
- flock/service.py +140 -0
- flock/store.py +69 -0
- flock/subscription.py +111 -0
- flock/themes/andromeda.toml +1 -1
- flock/themes/apple-system-colors.toml +1 -1
- flock/themes/arcoiris.toml +1 -1
- flock/themes/atomonelight.toml +1 -1
- flock/themes/ayu copy.toml +1 -1
- flock/themes/ayu-light.toml +1 -1
- flock/themes/belafonte-day.toml +1 -1
- flock/themes/belafonte-night.toml +1 -1
- flock/themes/blulocodark.toml +1 -1
- flock/themes/breeze.toml +1 -1
- flock/themes/broadcast.toml +1 -1
- flock/themes/brogrammer.toml +1 -1
- flock/themes/builtin-dark.toml +1 -1
- flock/themes/builtin-pastel-dark.toml +1 -1
- flock/themes/catppuccin-latte.toml +1 -1
- flock/themes/catppuccin-macchiato.toml +1 -1
- flock/themes/catppuccin-mocha.toml +1 -1
- flock/themes/cga.toml +1 -1
- flock/themes/chalk.toml +1 -1
- flock/themes/ciapre.toml +1 -1
- flock/themes/coffee-theme.toml +1 -1
- flock/themes/cyberpunkscarletprotocol.toml +1 -1
- flock/themes/dark+.toml +1 -1
- flock/themes/darkermatrix.toml +1 -1
- flock/themes/darkside.toml +1 -1
- flock/themes/desert.toml +1 -1
- flock/themes/django.toml +1 -1
- flock/themes/djangosmooth.toml +1 -1
- flock/themes/doomone.toml +1 -1
- flock/themes/dotgov.toml +1 -1
- flock/themes/dracula+.toml +1 -1
- flock/themes/duckbones.toml +1 -1
- flock/themes/encom.toml +1 -1
- flock/themes/espresso.toml +1 -1
- flock/themes/everblush.toml +1 -1
- flock/themes/fairyfloss.toml +1 -1
- flock/themes/fideloper.toml +1 -1
- flock/themes/fishtank.toml +1 -1
- flock/themes/flexoki-light.toml +1 -1
- flock/themes/floraverse.toml +1 -1
- flock/themes/framer.toml +1 -1
- flock/themes/galizur.toml +1 -1
- flock/themes/github.toml +1 -1
- flock/themes/grass.toml +1 -1
- flock/themes/grey-green.toml +1 -1
- flock/themes/gruvboxlight.toml +1 -1
- flock/themes/guezwhoz.toml +1 -1
- flock/themes/harper.toml +1 -1
- flock/themes/hax0r-blue.toml +1 -1
- flock/themes/hopscotch.256.toml +1 -1
- flock/themes/ic-green-ppl.toml +1 -1
- flock/themes/iceberg-dark.toml +1 -1
- flock/themes/japanesque.toml +1 -1
- flock/themes/jubi.toml +1 -1
- flock/themes/kibble.toml +1 -1
- flock/themes/kolorit.toml +1 -1
- flock/themes/kurokula.toml +1 -1
- flock/themes/materialdesigncolors.toml +1 -1
- flock/themes/matrix.toml +1 -1
- flock/themes/mellifluous.toml +1 -1
- flock/themes/midnight-in-mojave.toml +1 -1
- flock/themes/monokai-remastered.toml +1 -1
- flock/themes/monokai-soda.toml +1 -1
- flock/themes/neon.toml +1 -1
- flock/themes/neopolitan.toml +1 -1
- flock/themes/nord-light.toml +1 -1
- flock/themes/ocean.toml +1 -1
- flock/themes/onehalfdark.toml +1 -1
- flock/themes/onehalflight.toml +1 -1
- flock/themes/palenighthc.toml +1 -1
- flock/themes/paulmillr.toml +1 -1
- flock/themes/pencildark.toml +1 -1
- flock/themes/pnevma.toml +1 -1
- flock/themes/purple-rain.toml +1 -1
- flock/themes/purplepeter.toml +1 -1
- flock/themes/raycast-dark.toml +1 -1
- flock/themes/red-sands.toml +1 -1
- flock/themes/relaxed.toml +1 -1
- flock/themes/retro.toml +1 -1
- flock/themes/rose-pine.toml +1 -1
- flock/themes/royal.toml +1 -1
- flock/themes/ryuuko.toml +1 -1
- flock/themes/sakura.toml +1 -1
- flock/themes/scarlet-protocol.toml +1 -1
- flock/themes/seoulbones-dark.toml +1 -1
- flock/themes/shades-of-purple.toml +1 -1
- flock/themes/smyck.toml +1 -1
- flock/themes/softserver.toml +1 -1
- flock/themes/solarized-darcula.toml +1 -1
- flock/themes/square.toml +1 -1
- flock/themes/sugarplum.toml +1 -1
- flock/themes/thayer-bright.toml +1 -1
- flock/themes/tokyonight.toml +1 -1
- flock/themes/tomorrow.toml +1 -1
- flock/themes/ubuntu.toml +1 -1
- flock/themes/ultradark.toml +1 -1
- flock/themes/ultraviolent.toml +1 -1
- flock/themes/unikitty.toml +1 -1
- flock/themes/urple.toml +1 -1
- flock/themes/vesper.toml +1 -1
- flock/themes/vimbones.toml +1 -1
- flock/themes/wildcherry.toml +1 -1
- flock/themes/wilmersdorf.toml +1 -1
- flock/themes/wryan.toml +1 -1
- flock/themes/xcodedarkhc.toml +1 -1
- flock/themes/xcodelight.toml +1 -1
- flock/themes/zenbones-light.toml +1 -1
- flock/themes/zenwritten-dark.toml +1 -1
- flock/utilities.py +301 -0
- flock/{components/utility → utility}/output_utility_component.py +68 -53
- flock/visibility.py +107 -0
- flock_core-0.5.56b0.dist-info/METADATA +747 -0
- flock_core-0.5.56b0.dist-info/RECORD +398 -0
- flock_core-0.5.56b0.dist-info/entry_points.txt +2 -0
- {flock_core-0.5.0b28.dist-info → flock_core-0.5.56b0.dist-info}/licenses/LICENSE +1 -1
- flock/adapter/__init__.py +0 -14
- flock/adapter/azure_adapter.py +0 -68
- flock/adapter/chroma_adapter.py +0 -73
- flock/adapter/faiss_adapter.py +0 -97
- flock/adapter/pinecone_adapter.py +0 -51
- flock/adapter/vector_base.py +0 -47
- flock/cli/assets/release_notes.md +0 -140
- flock/cli/config.py +0 -8
- flock/cli/constants.py +0 -36
- flock/cli/create_agent.py +0 -1
- flock/cli/create_flock.py +0 -280
- flock/cli/execute_flock.py +0 -620
- flock/cli/load_agent.py +0 -1
- flock/cli/load_examples.py +0 -1
- flock/cli/load_flock.py +0 -192
- flock/cli/load_release_notes.py +0 -20
- flock/cli/loaded_flock_cli.py +0 -254
- flock/cli/manage_agents.py +0 -459
- flock/cli/registry_management.py +0 -889
- flock/cli/runner.py +0 -41
- flock/cli/settings.py +0 -857
- flock/cli/utils.py +0 -135
- flock/cli/view_results.py +0 -29
- flock/cli/yaml_editor.py +0 -396
- flock/components/__init__.py +0 -30
- flock/components/evaluation/__init__.py +0 -9
- flock/components/evaluation/declarative_evaluation_component.py +0 -606
- flock/components/routing/__init__.py +0 -15
- flock/components/routing/conditional_routing_component.py +0 -494
- flock/components/routing/default_routing_component.py +0 -103
- flock/components/routing/llm_routing_component.py +0 -206
- flock/components/utility/__init__.py +0 -22
- flock/components/utility/example_utility_component.py +0 -250
- flock/components/utility/feedback_utility_component.py +0 -206
- flock/components/utility/memory_utility_component.py +0 -550
- flock/components/utility/metrics_utility_component.py +0 -700
- flock/config.py +0 -61
- flock/core/__init__.py +0 -110
- flock/core/agent/__init__.py +0 -16
- flock/core/agent/default_agent.py +0 -216
- flock/core/agent/flock_agent_components.py +0 -104
- flock/core/agent/flock_agent_execution.py +0 -101
- flock/core/agent/flock_agent_integration.py +0 -260
- flock/core/agent/flock_agent_lifecycle.py +0 -186
- flock/core/agent/flock_agent_serialization.py +0 -381
- flock/core/api/__init__.py +0 -10
- flock/core/api/custom_endpoint.py +0 -45
- flock/core/api/endpoints.py +0 -254
- flock/core/api/main.py +0 -162
- flock/core/api/models.py +0 -97
- flock/core/api/run_store.py +0 -224
- flock/core/api/runner.py +0 -44
- flock/core/api/service.py +0 -214
- flock/core/component/__init__.py +0 -15
- flock/core/component/agent_component_base.py +0 -309
- flock/core/component/evaluation_component.py +0 -62
- flock/core/component/routing_component.py +0 -74
- flock/core/component/utility_component.py +0 -69
- flock/core/config/flock_agent_config.py +0 -58
- flock/core/config/scheduled_agent_config.py +0 -40
- flock/core/context/context.py +0 -213
- flock/core/context/context_manager.py +0 -37
- flock/core/context/context_vars.py +0 -10
- flock/core/evaluation/utils.py +0 -396
- flock/core/execution/batch_executor.py +0 -369
- flock/core/execution/evaluation_executor.py +0 -438
- flock/core/execution/local_executor.py +0 -31
- flock/core/execution/opik_executor.py +0 -103
- flock/core/execution/temporal_executor.py +0 -164
- flock/core/flock.py +0 -634
- flock/core/flock_agent.py +0 -336
- flock/core/flock_factory.py +0 -613
- flock/core/flock_scheduler.py +0 -166
- flock/core/flock_server_manager.py +0 -136
- flock/core/interpreter/python_interpreter.py +0 -689
- flock/core/mcp/__init__.py +0 -1
- flock/core/mcp/flock_mcp_server.py +0 -680
- flock/core/mcp/mcp_client_manager.py +0 -201
- flock/core/mcp/types/__init__.py +0 -1
- flock/core/mixin/dspy_integration.py +0 -403
- flock/core/mixin/prompt_parser.py +0 -125
- flock/core/orchestration/__init__.py +0 -15
- flock/core/orchestration/flock_batch_processor.py +0 -94
- flock/core/orchestration/flock_evaluator.py +0 -113
- flock/core/orchestration/flock_execution.py +0 -295
- flock/core/orchestration/flock_initialization.py +0 -149
- flock/core/orchestration/flock_server_manager.py +0 -67
- flock/core/orchestration/flock_web_server.py +0 -117
- flock/core/registry/__init__.py +0 -45
- flock/core/registry/agent_registry.py +0 -69
- flock/core/registry/callable_registry.py +0 -139
- flock/core/registry/component_discovery.py +0 -142
- flock/core/registry/component_registry.py +0 -64
- flock/core/registry/config_mapping.py +0 -64
- flock/core/registry/decorators.py +0 -137
- flock/core/registry/registry_hub.py +0 -205
- flock/core/registry/server_registry.py +0 -57
- flock/core/registry/type_registry.py +0 -86
- flock/core/serialization/__init__.py +0 -13
- flock/core/serialization/callable_registry.py +0 -52
- flock/core/serialization/flock_serializer.py +0 -832
- flock/core/serialization/json_encoder.py +0 -41
- flock/core/serialization/secure_serializer.py +0 -175
- flock/core/serialization/serializable.py +0 -342
- flock/core/serialization/serialization_utils.py +0 -412
- flock/core/util/file_path_utils.py +0 -223
- flock/core/util/hydrator.py +0 -309
- flock/core/util/input_resolver.py +0 -164
- flock/core/util/loader.py +0 -59
- flock/core/util/splitter.py +0 -219
- flock/di.py +0 -27
- flock/platform/docker_tools.py +0 -49
- flock/platform/jaeger_install.py +0 -86
- flock/webapp/__init__.py +0 -1
- flock/webapp/app/__init__.py +0 -0
- flock/webapp/app/api/__init__.py +0 -0
- flock/webapp/app/api/agent_management.py +0 -241
- flock/webapp/app/api/execution.py +0 -709
- flock/webapp/app/api/flock_management.py +0 -129
- flock/webapp/app/api/registry_viewer.py +0 -30
- flock/webapp/app/chat.py +0 -665
- flock/webapp/app/config.py +0 -104
- flock/webapp/app/dependencies.py +0 -117
- flock/webapp/app/main.py +0 -1070
- flock/webapp/app/middleware.py +0 -113
- flock/webapp/app/models_ui.py +0 -7
- flock/webapp/app/services/__init__.py +0 -0
- flock/webapp/app/services/feedback_file_service.py +0 -363
- flock/webapp/app/services/flock_service.py +0 -337
- flock/webapp/app/services/sharing_models.py +0 -81
- flock/webapp/app/services/sharing_store.py +0 -762
- flock/webapp/app/templates/theme_mapper.html +0 -326
- flock/webapp/app/theme_mapper.py +0 -812
- flock/webapp/app/utils.py +0 -85
- flock/webapp/run.py +0 -215
- flock/webapp/static/css/chat.css +0 -301
- flock/webapp/static/css/components.css +0 -167
- flock/webapp/static/css/header.css +0 -39
- flock/webapp/static/css/layout.css +0 -46
- flock/webapp/static/css/sidebar.css +0 -127
- flock/webapp/static/css/two-pane.css +0 -48
- flock/webapp/templates/base.html +0 -200
- flock/webapp/templates/chat.html +0 -152
- flock/webapp/templates/chat_settings.html +0 -19
- flock/webapp/templates/flock_editor.html +0 -16
- flock/webapp/templates/index.html +0 -12
- flock/webapp/templates/partials/_agent_detail_form.html +0 -93
- flock/webapp/templates/partials/_agent_list.html +0 -18
- flock/webapp/templates/partials/_agent_manager_view.html +0 -51
- flock/webapp/templates/partials/_agent_tools_checklist.html +0 -14
- flock/webapp/templates/partials/_chat_container.html +0 -15
- flock/webapp/templates/partials/_chat_messages.html +0 -57
- flock/webapp/templates/partials/_chat_settings_form.html +0 -85
- flock/webapp/templates/partials/_create_flock_form.html +0 -50
- flock/webapp/templates/partials/_dashboard_flock_detail.html +0 -17
- flock/webapp/templates/partials/_dashboard_flock_file_list.html +0 -16
- flock/webapp/templates/partials/_dashboard_flock_properties_preview.html +0 -28
- flock/webapp/templates/partials/_dashboard_upload_flock_form.html +0 -16
- flock/webapp/templates/partials/_dynamic_input_form_content.html +0 -22
- flock/webapp/templates/partials/_env_vars_table.html +0 -23
- flock/webapp/templates/partials/_execution_form.html +0 -118
- flock/webapp/templates/partials/_execution_view_container.html +0 -28
- flock/webapp/templates/partials/_flock_file_list.html +0 -23
- flock/webapp/templates/partials/_flock_properties_form.html +0 -52
- flock/webapp/templates/partials/_flock_upload_form.html +0 -16
- flock/webapp/templates/partials/_header_flock_status.html +0 -5
- flock/webapp/templates/partials/_load_manager_view.html +0 -49
- flock/webapp/templates/partials/_registry_table.html +0 -25
- flock/webapp/templates/partials/_registry_viewer_content.html +0 -70
- flock/webapp/templates/partials/_results_display.html +0 -78
- flock/webapp/templates/partials/_settings_env_content.html +0 -9
- flock/webapp/templates/partials/_settings_theme_content.html +0 -14
- flock/webapp/templates/partials/_settings_view.html +0 -36
- flock/webapp/templates/partials/_share_chat_link_snippet.html +0 -11
- flock/webapp/templates/partials/_share_link_snippet.html +0 -35
- flock/webapp/templates/partials/_sidebar.html +0 -74
- flock/webapp/templates/partials/_streaming_results_container.html +0 -195
- flock/webapp/templates/partials/_structured_data_view.html +0 -40
- flock/webapp/templates/partials/_theme_preview.html +0 -36
- flock/webapp/templates/registry_viewer.html +0 -84
- flock/webapp/templates/shared_run_page.html +0 -140
- flock/workflow/__init__.py +0 -0
- flock/workflow/activities.py +0 -196
- flock/workflow/agent_activities.py +0 -24
- flock/workflow/agent_execution_activity.py +0 -202
- flock/workflow/flock_workflow.py +0 -214
- flock/workflow/temporal_config.py +0 -96
- flock/workflow/temporal_setup.py +0 -68
- flock_core-0.5.0b28.dist-info/METADATA +0 -274
- flock_core-0.5.0b28.dist-info/RECORD +0 -561
- flock_core-0.5.0b28.dist-info/entry_points.txt +0 -2
- /flock/{core/logging → logging}/formatters/themes.py +0 -0
- /flock/{core/logging → logging}/span_middleware/baggage_span_processor.py +0 -0
- /flock/{core/mcp → mcp}/util/__init__.py +0 -0
- {flock_core-0.5.0b28.dist-info → flock_core-0.5.56b0.dist-info}/WHEEL +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"""Base Config for MCP Clients."""
|
|
2
2
|
|
|
3
3
|
import importlib
|
|
4
|
-
from typing import Any, Literal, TypeVar
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Literal, TypeVar
|
|
5
5
|
|
|
6
|
-
import httpx
|
|
7
6
|
from pydantic import BaseModel, ConfigDict, Field, create_model
|
|
7
|
+
from typing_extensions import Self
|
|
8
8
|
|
|
9
|
-
from flock.
|
|
9
|
+
from flock.mcp.types import (
|
|
10
10
|
FlockListRootsMCPCallback,
|
|
11
11
|
FlockLoggingMCPCallback,
|
|
12
12
|
FlockMessageHandlerMCPCallback,
|
|
@@ -18,11 +18,11 @@ from flock.core.mcp.types.types import (
|
|
|
18
18
|
StreamableHttpServerParameters,
|
|
19
19
|
WebsocketServerParameters,
|
|
20
20
|
)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
import httpx
|
|
25
|
+
|
|
26
26
|
|
|
27
27
|
LoggingLevel = Literal[
|
|
28
28
|
"debug",
|
|
@@ -43,7 +43,7 @@ D = TypeVar("D", bound="FlockMCPCachingConfiguration")
|
|
|
43
43
|
E = TypeVar("E", bound="FlockMCPFeatureConfiguration")
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
class FlockMCPCachingConfiguration(BaseModel
|
|
46
|
+
class FlockMCPCachingConfiguration(BaseModel):
|
|
47
47
|
"""Configuration for Caching in Clients."""
|
|
48
48
|
|
|
49
49
|
tool_cache_max_size: float = Field(
|
|
@@ -98,19 +98,17 @@ class FlockMCPCachingConfiguration(BaseModel, Serializable):
|
|
|
98
98
|
)
|
|
99
99
|
|
|
100
100
|
@classmethod
|
|
101
|
-
def from_dict(cls
|
|
101
|
+
def from_dict(cls, data: dict[str, Any]) -> Self:
|
|
102
102
|
"""Deserialize from a dict."""
|
|
103
|
-
return cls(**
|
|
103
|
+
return cls(**dict(data.items()))
|
|
104
104
|
|
|
105
105
|
@classmethod
|
|
106
|
-
def with_fields(cls
|
|
106
|
+
def with_fields(cls, **field_definitions) -> type[Self]:
|
|
107
107
|
"""Create a new config class with additional fields."""
|
|
108
|
-
return create_model(
|
|
109
|
-
f"Dynamic{cls.__name__}", __base__=cls, **field_definitions
|
|
110
|
-
)
|
|
108
|
+
return create_model(f"Dynamic{cls.__name__}", __base__=cls, **field_definitions)
|
|
111
109
|
|
|
112
110
|
|
|
113
|
-
class FlockMCPCallbackConfiguration(BaseModel
|
|
111
|
+
class FlockMCPCallbackConfiguration(BaseModel):
|
|
114
112
|
"""Base Configuration Class for Callbacks for Clients."""
|
|
115
113
|
|
|
116
114
|
sampling_callback: FlockSamplingMCPCallback | None = Field(
|
|
@@ -136,59 +134,21 @@ class FlockMCPCallbackConfiguration(BaseModel, Serializable):
|
|
|
136
134
|
|
|
137
135
|
def to_dict(self, path_type: str = "relative"):
|
|
138
136
|
"""Serialize the object."""
|
|
139
|
-
#
|
|
140
|
-
|
|
141
|
-
if self.sampling_callback:
|
|
142
|
-
sampling_callback_data = serialize_item(self.sampling_callback)
|
|
143
|
-
data["sampling_callback"] = sampling_callback_data
|
|
144
|
-
|
|
145
|
-
if self.list_roots_callback:
|
|
146
|
-
list_roots_callback_data = serialize_item(self.list_roots_callback)
|
|
147
|
-
data["list_roots_callback"] = list_roots_callback_data
|
|
148
|
-
|
|
149
|
-
if self.logging_callback:
|
|
150
|
-
logging_callback_data = serialize_item(self.logging_callback)
|
|
151
|
-
data["logging_callback"] = logging_callback_data
|
|
152
|
-
|
|
153
|
-
if self.message_handler:
|
|
154
|
-
message_handler_data = serialize_item(self.message_handler)
|
|
155
|
-
data["message_handler"] = message_handler_data
|
|
156
|
-
|
|
157
|
-
return data
|
|
137
|
+
# Callbacks are set programmatically and cannot be serialized
|
|
138
|
+
return {}
|
|
158
139
|
|
|
159
140
|
@classmethod
|
|
160
|
-
def from_dict(cls
|
|
141
|
+
def from_dict(cls, data: dict[str, Any]) -> Self:
|
|
161
142
|
"""Deserialize from a dict."""
|
|
162
|
-
|
|
163
|
-
if data:
|
|
164
|
-
if "sampling_callback" in data:
|
|
165
|
-
instance.sampling_callback = deserialize_item(
|
|
166
|
-
data["sampling_callback"]
|
|
167
|
-
)
|
|
168
|
-
if "list_roots_callback" in data:
|
|
169
|
-
instance.list_roots_callback = deserialize_item(
|
|
170
|
-
data["list_roots_callback"]
|
|
171
|
-
)
|
|
172
|
-
if "logging_callback" in data:
|
|
173
|
-
instance.logging_callback = deserialize_item(
|
|
174
|
-
data["logging_callback"]
|
|
175
|
-
)
|
|
176
|
-
if "message_handler" in data:
|
|
177
|
-
instance.message_handler = deserialize_item(
|
|
178
|
-
data["message_handler"]
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
return instance
|
|
143
|
+
return cls()
|
|
182
144
|
|
|
183
145
|
@classmethod
|
|
184
|
-
def with_fields(cls
|
|
146
|
+
def with_fields(cls, **field_definitions) -> type[Self]:
|
|
185
147
|
"""Create a new config class with additional fields."""
|
|
186
|
-
return create_model(
|
|
187
|
-
f"Dynamic{cls.__name__}", __base__=cls, **field_definitions
|
|
188
|
-
)
|
|
148
|
+
return create_model(f"Dynamic{cls.__name__}", __base__=cls, **field_definitions)
|
|
189
149
|
|
|
190
150
|
|
|
191
|
-
class FlockMCPConnectionConfiguration(BaseModel
|
|
151
|
+
class FlockMCPConnectionConfiguration(BaseModel):
|
|
192
152
|
"""Base Configuration Class for Connection Parameters for a client."""
|
|
193
153
|
|
|
194
154
|
max_retries: int = Field(
|
|
@@ -200,17 +160,15 @@ class FlockMCPConnectionConfiguration(BaseModel, Serializable):
|
|
|
200
160
|
..., description="Connection parameters for the server."
|
|
201
161
|
)
|
|
202
162
|
|
|
203
|
-
transport_type: Literal[
|
|
204
|
-
|
|
205
|
-
|
|
163
|
+
transport_type: Literal["stdio", "websockets", "sse", "streamable_http", "custom"] = Field(
|
|
164
|
+
..., description="Type of transport to use."
|
|
165
|
+
)
|
|
206
166
|
|
|
207
167
|
mount_points: list[MCPRoot] | None = Field(
|
|
208
168
|
default=None, description="Initial Mountpoints to operate under."
|
|
209
169
|
)
|
|
210
170
|
|
|
211
|
-
read_timeout_seconds: float | int = Field(
|
|
212
|
-
default=60 * 5, description="Read Timeout."
|
|
213
|
-
)
|
|
171
|
+
read_timeout_seconds: float | int = Field(default=60 * 5, description="Read Timeout.")
|
|
214
172
|
|
|
215
173
|
server_logging_level: LoggingLevel = Field(
|
|
216
174
|
default="error",
|
|
@@ -230,14 +188,12 @@ class FlockMCPConnectionConfiguration(BaseModel, Serializable):
|
|
|
230
188
|
mode="json",
|
|
231
189
|
)
|
|
232
190
|
|
|
233
|
-
data["connection_parameters"] = self.connection_parameters.to_dict(
|
|
234
|
-
path_type=path_type
|
|
235
|
-
)
|
|
191
|
+
data["connection_parameters"] = self.connection_parameters.to_dict(path_type=path_type)
|
|
236
192
|
|
|
237
193
|
return data
|
|
238
194
|
|
|
239
195
|
@classmethod
|
|
240
|
-
def from_dict(cls
|
|
196
|
+
def from_dict(cls, data: dict[str, Any]) -> Self:
|
|
241
197
|
"""Deserialize from dict."""
|
|
242
198
|
connection_params = data.get("connection_parameters")
|
|
243
199
|
connection_params_obj = None
|
|
@@ -248,13 +204,13 @@ class FlockMCPConnectionConfiguration(BaseModel, Serializable):
|
|
|
248
204
|
if auth_spec:
|
|
249
205
|
# find the concrete implementation and
|
|
250
206
|
# instantiate it.
|
|
251
|
-
|
|
207
|
+
# find the concrete implementation for auth and instatiate it.
|
|
252
208
|
impl = auth_spec.get("implementation", None)
|
|
253
209
|
params = auth_spec.get("params", None)
|
|
254
210
|
if impl and params:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
211
|
+
mod = importlib.import_module(impl["module_path"])
|
|
212
|
+
real_cls = getattr(mod, impl["class_name"])
|
|
213
|
+
auth_obj = real_cls(**dict(params.items()))
|
|
258
214
|
|
|
259
215
|
if auth_obj:
|
|
260
216
|
connection_params["auth"] = auth_obj
|
|
@@ -264,41 +220,36 @@ class FlockMCPConnectionConfiguration(BaseModel, Serializable):
|
|
|
264
220
|
match kind:
|
|
265
221
|
case "stdio":
|
|
266
222
|
connection_params_obj = StdioServerParameters(
|
|
267
|
-
**
|
|
223
|
+
**dict(connection_params.items())
|
|
268
224
|
)
|
|
269
225
|
case "websockets":
|
|
270
226
|
connection_params_obj = WebsocketServerParameters(
|
|
271
|
-
**
|
|
227
|
+
**dict(connection_params.items())
|
|
272
228
|
)
|
|
273
229
|
case "streamable_http":
|
|
274
230
|
connection_params_obj = StreamableHttpServerParameters(
|
|
275
|
-
**
|
|
231
|
+
**dict(connection_params.items())
|
|
276
232
|
)
|
|
277
233
|
case "sse":
|
|
278
234
|
connection_params_obj = SseServerParameters(
|
|
279
|
-
**
|
|
235
|
+
**dict(connection_params.items())
|
|
280
236
|
)
|
|
281
237
|
case _:
|
|
282
238
|
# handle custom server params
|
|
283
|
-
connection_params_obj = ServerParameters(
|
|
284
|
-
**{k: v for k, v in connection_params.items()}
|
|
285
|
-
)
|
|
239
|
+
connection_params_obj = ServerParameters(**dict(connection_params.items()))
|
|
286
240
|
|
|
287
241
|
if connection_params_obj:
|
|
288
242
|
data["connection_parameters"] = connection_params_obj
|
|
289
|
-
return cls(**
|
|
290
|
-
|
|
291
|
-
raise ValueError("No connection parameters provided.")
|
|
243
|
+
return cls(**dict(data.items()))
|
|
244
|
+
raise ValueError("No connection parameters provided.")
|
|
292
245
|
|
|
293
246
|
@classmethod
|
|
294
|
-
def with_fields(cls
|
|
247
|
+
def with_fields(cls, **field_definitions) -> type[Self]:
|
|
295
248
|
"""Create a new config class with additional fields."""
|
|
296
|
-
return create_model(
|
|
297
|
-
f"Dynamic{cls.__name__}", __base__=cls, **field_definitions
|
|
298
|
-
)
|
|
249
|
+
return create_model(f"Dynamic{cls.__name__}", __base__=cls, **field_definitions)
|
|
299
250
|
|
|
300
251
|
|
|
301
|
-
class FlockMCPFeatureConfiguration(BaseModel
|
|
252
|
+
class FlockMCPFeatureConfiguration(BaseModel):
|
|
302
253
|
"""Base Configuration Class for switching MCP Features on and off."""
|
|
303
254
|
|
|
304
255
|
roots_enabled: bool = Field(
|
|
@@ -319,10 +270,10 @@ class FlockMCPFeatureConfiguration(BaseModel, Serializable):
|
|
|
319
270
|
tool_whitelist: list[str] | None = Field(
|
|
320
271
|
default=None,
|
|
321
272
|
description="Whitelist of tool names that are enabled for this MCP server. "
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
273
|
+
"If provided, only tools with names in this list will be available "
|
|
274
|
+
"from this server. Used in conjunction with allow_all_tools setting. "
|
|
275
|
+
"Note: Agent-level tool filtering is generally preferred over "
|
|
276
|
+
"server-level filtering for better granular control.",
|
|
326
277
|
)
|
|
327
278
|
|
|
328
279
|
prompts_enabled: bool = Field(
|
|
@@ -345,34 +296,30 @@ class FlockMCPFeatureConfiguration(BaseModel, Serializable):
|
|
|
345
296
|
@classmethod
|
|
346
297
|
def from_dict(cls, data: dict[str, Any]):
|
|
347
298
|
"""Deserialize from a dict."""
|
|
348
|
-
return cls(**
|
|
299
|
+
return cls(**dict(data.items()))
|
|
349
300
|
|
|
350
301
|
@classmethod
|
|
351
|
-
def with_fields(cls
|
|
302
|
+
def with_fields(cls, **field_definitions) -> type[Self]:
|
|
352
303
|
"""Create a new config class with additional fields."""
|
|
353
|
-
return create_model(
|
|
354
|
-
f"Dynamic{cls.__name__}", __base__=cls, **field_definitions
|
|
355
|
-
)
|
|
304
|
+
return create_model(f"Dynamic{cls.__name__}", __base__=cls, **field_definitions)
|
|
356
305
|
|
|
357
306
|
|
|
358
|
-
class FlockMCPConfiguration(BaseModel
|
|
307
|
+
class FlockMCPConfiguration(BaseModel):
|
|
359
308
|
"""Base Configuration Class for MCP Clients.
|
|
360
309
|
|
|
361
310
|
Each Client should implement their own config
|
|
362
311
|
model by inheriting from this class.
|
|
363
312
|
"""
|
|
364
313
|
|
|
365
|
-
name: str = Field(
|
|
366
|
-
..., description="Name of the server the client connects to."
|
|
367
|
-
)
|
|
314
|
+
name: str = Field(..., description="Name of the server the client connects to.")
|
|
368
315
|
|
|
369
316
|
allow_all_tools: bool = Field(
|
|
370
317
|
default=True,
|
|
371
318
|
description="Whether to allow usage of all tools from this MCP server. "
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
319
|
+
"When True (default), all tools are available unless restricted "
|
|
320
|
+
"by tool_whitelist. When False, tool access is controlled entirely "
|
|
321
|
+
"by tool_whitelist (if provided). Setting to False with no whitelist "
|
|
322
|
+
"will block all tools from this server.",
|
|
376
323
|
)
|
|
377
324
|
|
|
378
325
|
connection_config: FlockMCPConnectionConfiguration = Field(
|
|
@@ -425,16 +372,14 @@ class FlockMCPConfiguration(BaseModel, Serializable):
|
|
|
425
372
|
return data
|
|
426
373
|
|
|
427
374
|
@classmethod
|
|
428
|
-
def from_dict(cls
|
|
375
|
+
def from_dict(cls, data: dict[str, Any]) -> Self:
|
|
429
376
|
"""Deserialize the class."""
|
|
430
377
|
connection_config = data.pop("connection_config", None)
|
|
431
378
|
caching_config = data.pop("caching_config", None)
|
|
432
379
|
feature_config = data.pop("feature_config", None)
|
|
433
380
|
callback_config = data.pop("callback_config", None)
|
|
434
381
|
|
|
435
|
-
instance_data: dict[str, Any] = {
|
|
436
|
-
"name": data["name"]
|
|
437
|
-
}
|
|
382
|
+
instance_data: dict[str, Any] = {"name": data["name"]}
|
|
438
383
|
|
|
439
384
|
if connection_config:
|
|
440
385
|
# Forcing a square into a round hole
|
|
@@ -446,7 +391,9 @@ class FlockMCPConfiguration(BaseModel, Serializable):
|
|
|
446
391
|
config_cls = FlockMCPConnectionConfiguration
|
|
447
392
|
instance_data["connection_config"] = config_cls.from_dict(connection_config)
|
|
448
393
|
else:
|
|
449
|
-
raise ValueError(
|
|
394
|
+
raise ValueError(
|
|
395
|
+
f"connection_config MUST be specified for '{data.get('name', 'unknown_server')}"
|
|
396
|
+
)
|
|
450
397
|
|
|
451
398
|
if caching_config:
|
|
452
399
|
try:
|
|
@@ -481,11 +428,9 @@ class FlockMCPConfiguration(BaseModel, Serializable):
|
|
|
481
428
|
else:
|
|
482
429
|
instance_data["callback_config"] = FlockMCPCallbackConfiguration()
|
|
483
430
|
|
|
484
|
-
return cls(**
|
|
431
|
+
return cls(**dict(instance_data.items()))
|
|
485
432
|
|
|
486
433
|
@classmethod
|
|
487
|
-
def with_fields(cls
|
|
434
|
+
def with_fields(cls, **field_definitions) -> type[Self]:
|
|
488
435
|
"""Create a new config class with additional fields."""
|
|
489
|
-
return create_model(
|
|
490
|
-
f"Dynamic{cls.__name__}", __base__=cls, **field_definitions
|
|
491
|
-
)
|
|
436
|
+
return create_model(f"Dynamic{cls.__name__}", __base__=cls, **field_definitions)
|
flock/mcp/manager.py
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"""MCP Client Manager for Connection Pooling and Lifecycle Management.
|
|
2
|
+
|
|
3
|
+
This module provides the FlockMCPClientManager class which manages MCP client
|
|
4
|
+
connections with per-(agent_id, run_id) isolation and lazy connection establishment.
|
|
5
|
+
|
|
6
|
+
Architecture Decisions:
|
|
7
|
+
- AD004: Per-(agent_id, run_id) Connection Isolation
|
|
8
|
+
Each unique (agent_id, run_id) pair gets its own set of isolated MCP connections
|
|
9
|
+
- AD005: Lazy Connection Establishment
|
|
10
|
+
Connections are only established when first requested
|
|
11
|
+
- AD007: Graceful Degradation on MCP Failures
|
|
12
|
+
Failures to connect to individual servers don't prevent agent execution
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import asyncio
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
from flock.logging.logging import get_logger
|
|
19
|
+
from flock.mcp.client import FlockMCPClient
|
|
20
|
+
from flock.mcp.config import FlockMCPConfiguration
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
logger = get_logger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class FlockMCPClientManager:
|
|
27
|
+
"""Manages MCP client connections with per-(agent_id, run_id) isolation.
|
|
28
|
+
|
|
29
|
+
This manager implements lazy connection pooling where clients are only
|
|
30
|
+
initialized when first requested. Each unique (agent_id, run_id) pair
|
|
31
|
+
gets its own set of isolated MCP connections.
|
|
32
|
+
|
|
33
|
+
Architecture Decision: AD004 - Per-(agent_id, run_id) Connection Isolation
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
```python
|
|
37
|
+
# Initialize manager with configurations
|
|
38
|
+
configs = {
|
|
39
|
+
"filesystem": FlockMCPConfiguration(
|
|
40
|
+
name="filesystem",
|
|
41
|
+
connection_config=connection_config,
|
|
42
|
+
feature_config=feature_config
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
manager = FlockMCPClientManager(configs)
|
|
46
|
+
|
|
47
|
+
# Get client for specific agent and run
|
|
48
|
+
client = await manager.get_client("filesystem", "agent_1", "run_123")
|
|
49
|
+
|
|
50
|
+
# Get all tools for agent
|
|
51
|
+
tools = await manager.get_tools_for_agent(
|
|
52
|
+
"agent_1", "run_123", {"filesystem"}
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Cleanup after run completes
|
|
56
|
+
await manager.cleanup_run("agent_1", "run_123")
|
|
57
|
+
```
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(self, configs: dict[str, FlockMCPConfiguration]):
|
|
61
|
+
"""Initialize the manager with MCP server configurations.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
configs: Dictionary mapping server names to their configurations
|
|
65
|
+
"""
|
|
66
|
+
self._configs = configs
|
|
67
|
+
# Pool structure: (agent_id, run_id) → server_name → FlockMCPClient
|
|
68
|
+
self._pool: dict[tuple[str, str], dict[str, FlockMCPClient]] = {}
|
|
69
|
+
self._lock = asyncio.Lock()
|
|
70
|
+
|
|
71
|
+
async def get_client(self, server_name: str, agent_id: str, run_id: str) -> FlockMCPClient:
|
|
72
|
+
"""Get or create an MCP client for the given context.
|
|
73
|
+
|
|
74
|
+
Architecture Decision: AD005 - Lazy Connection Establishment
|
|
75
|
+
Connections are only established when first requested.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
server_name: Name of the MCP server
|
|
79
|
+
agent_id: Agent requesting the client
|
|
80
|
+
run_id: Current run identifier
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
FlockMCPClient instance ready for use
|
|
84
|
+
|
|
85
|
+
Raises:
|
|
86
|
+
ValueError: If server_name not registered
|
|
87
|
+
"""
|
|
88
|
+
if server_name not in self._configs:
|
|
89
|
+
raise ValueError(
|
|
90
|
+
f"MCP server '{server_name}' not registered. "
|
|
91
|
+
f"Available servers: {list(self._configs.keys())}"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
key = (agent_id, run_id)
|
|
95
|
+
|
|
96
|
+
async with self._lock:
|
|
97
|
+
# Check if we have a client pool for this (agent, run)
|
|
98
|
+
if key not in self._pool:
|
|
99
|
+
self._pool[key] = {}
|
|
100
|
+
|
|
101
|
+
# Check if we have a client for this server
|
|
102
|
+
if server_name not in self._pool[key]:
|
|
103
|
+
logger.info(
|
|
104
|
+
f"Creating new MCP client for server '{server_name}' "
|
|
105
|
+
f"(agent={agent_id}, run={run_id})"
|
|
106
|
+
)
|
|
107
|
+
config = self._configs[server_name]
|
|
108
|
+
|
|
109
|
+
# Instantiate the correct concrete client class based on transport type
|
|
110
|
+
# Lazy import to avoid requiring all dependencies
|
|
111
|
+
transport_type = config.connection_config.transport_type
|
|
112
|
+
if transport_type == "stdio":
|
|
113
|
+
from flock.mcp.servers.stdio.flock_stdio_server import (
|
|
114
|
+
FlockStdioClient,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
client = FlockStdioClient(config=config)
|
|
118
|
+
elif transport_type == "sse":
|
|
119
|
+
from flock.mcp.servers.sse.flock_sse_server import (
|
|
120
|
+
FlockSSEClient,
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
client = FlockSSEClient(config=config)
|
|
124
|
+
elif transport_type == "websocket":
|
|
125
|
+
from flock.mcp.servers.websockets.flock_websocket_server import (
|
|
126
|
+
FlockWSClient,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
client = FlockWSClient(config=config)
|
|
130
|
+
elif transport_type == "streamable_http":
|
|
131
|
+
from flock.mcp.servers.streamable_http.flock_streamable_http_server import (
|
|
132
|
+
FlockStreamableHttpClient,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
client = FlockStreamableHttpClient(config=config)
|
|
136
|
+
else:
|
|
137
|
+
raise ValueError(
|
|
138
|
+
f"Unsupported transport type: {transport_type}. "
|
|
139
|
+
f"Supported types: stdio, sse, websocket, streamable_http"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
await client._connect()
|
|
143
|
+
self._pool[key][server_name] = client
|
|
144
|
+
|
|
145
|
+
return self._pool[key][server_name]
|
|
146
|
+
|
|
147
|
+
async def get_tools_for_agent(
|
|
148
|
+
self, agent_id: str, run_id: str, server_names: set[str]
|
|
149
|
+
) -> dict[str, Any]:
|
|
150
|
+
"""Get all tools from specified servers for an agent.
|
|
151
|
+
|
|
152
|
+
Architecture Decision: AD003 - Tool Namespacing
|
|
153
|
+
All tools are returned with format: {server}__{tool}
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
agent_id: Agent requesting tools
|
|
157
|
+
run_id: Current run identifier
|
|
158
|
+
server_names: Set of MCP server names to fetch tools from
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
Dictionary mapping namespaced tool names to tool definitions
|
|
162
|
+
|
|
163
|
+
Note:
|
|
164
|
+
Architecture Decision: AD007 - Graceful Degradation
|
|
165
|
+
If a server fails to load, we log the error and continue with
|
|
166
|
+
other servers rather than failing the entire operation.
|
|
167
|
+
"""
|
|
168
|
+
tools = {}
|
|
169
|
+
|
|
170
|
+
for server_name in server_names:
|
|
171
|
+
try:
|
|
172
|
+
client = await self.get_client(server_name, agent_id, run_id)
|
|
173
|
+
server_tools = await client.get_tools(agent_id, run_id)
|
|
174
|
+
|
|
175
|
+
# Apply namespacing: AD003
|
|
176
|
+
for tool in server_tools:
|
|
177
|
+
namespaced_name = f"{server_name}__{tool.name}"
|
|
178
|
+
tools[namespaced_name] = {
|
|
179
|
+
"server_name": server_name,
|
|
180
|
+
"original_name": tool.name,
|
|
181
|
+
"tool": tool,
|
|
182
|
+
"client": client,
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
logger.debug(
|
|
186
|
+
f"Loaded {len(server_tools)} tools from server '{server_name}' "
|
|
187
|
+
f"for agent {agent_id}"
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
except Exception as e:
|
|
191
|
+
# Architecture Decision: AD007 - Graceful Degradation
|
|
192
|
+
logger.exception(
|
|
193
|
+
f"Failed to load tools from MCP server '{server_name}': {e}. "
|
|
194
|
+
f"Agent {agent_id} will continue without these tools."
|
|
195
|
+
)
|
|
196
|
+
# Continue loading other servers
|
|
197
|
+
continue
|
|
198
|
+
|
|
199
|
+
return tools
|
|
200
|
+
|
|
201
|
+
async def cleanup_run(self, agent_id: str, run_id: str) -> None:
|
|
202
|
+
"""Clean up all MCP connections for a completed run.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
agent_id: Agent identifier
|
|
206
|
+
run_id: Run identifier to clean up
|
|
207
|
+
"""
|
|
208
|
+
key = (agent_id, run_id)
|
|
209
|
+
|
|
210
|
+
async with self._lock:
|
|
211
|
+
if key in self._pool:
|
|
212
|
+
logger.info(f"Cleaning up MCP connections for run {run_id}")
|
|
213
|
+
clients = self._pool[key]
|
|
214
|
+
|
|
215
|
+
# Disconnect all clients for this run
|
|
216
|
+
for server_name, client in clients.items():
|
|
217
|
+
try:
|
|
218
|
+
await client.disconnect()
|
|
219
|
+
logger.debug(f"Disconnected from MCP server '{server_name}'")
|
|
220
|
+
except Exception as e:
|
|
221
|
+
logger.warning(f"Error disconnecting from '{server_name}': {e}")
|
|
222
|
+
|
|
223
|
+
# Remove from pool
|
|
224
|
+
del self._pool[key]
|
|
225
|
+
|
|
226
|
+
async def cleanup_all(self) -> None:
|
|
227
|
+
"""Clean up all MCP connections (orchestrator shutdown)."""
|
|
228
|
+
async with self._lock:
|
|
229
|
+
logger.info("Shutting down all MCP connections")
|
|
230
|
+
|
|
231
|
+
for _key, clients in self._pool.items():
|
|
232
|
+
for server_name, client in clients.items():
|
|
233
|
+
try:
|
|
234
|
+
await client.disconnect()
|
|
235
|
+
except Exception as e:
|
|
236
|
+
logger.warning(f"Error disconnecting from '{server_name}': {e}")
|
|
237
|
+
|
|
238
|
+
self._pool.clear()
|
|
239
|
+
logger.info("All MCP connections closed")
|
|
240
|
+
|
|
241
|
+
def list_servers(self) -> dict[str, dict[str, Any]]:
|
|
242
|
+
"""List all registered MCP servers with their configurations.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Dictionary mapping server names to configuration metadata
|
|
246
|
+
"""
|
|
247
|
+
return {
|
|
248
|
+
name: {
|
|
249
|
+
"transport_type": config.connection_config.transport_type,
|
|
250
|
+
"tools_enabled": config.feature_config.tools_enabled,
|
|
251
|
+
"prompts_enabled": config.feature_config.prompts_enabled,
|
|
252
|
+
"sampling_enabled": config.feature_config.sampling_enabled,
|
|
253
|
+
}
|
|
254
|
+
for name, config in self._configs.items()
|
|
255
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"""Default SSE Server Implementation for
|
|
1
|
+
"""Default SSE Server Implementation for flock."""
|