agent_os_kernel 3.1.0__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.
- agent_control_plane/__init__.py +662 -0
- agent_control_plane/a2a_adapter.py +543 -0
- agent_control_plane/adapter.py +417 -0
- agent_control_plane/agent_hibernation.py +394 -0
- agent_control_plane/agent_kernel.py +470 -0
- agent_control_plane/compliance.py +720 -0
- agent_control_plane/constraint_graphs.py +478 -0
- agent_control_plane/control_plane.py +854 -0
- agent_control_plane/example_executors.py +195 -0
- agent_control_plane/execution_engine.py +231 -0
- agent_control_plane/flight_recorder.py +846 -0
- agent_control_plane/governance_layer.py +435 -0
- agent_control_plane/hf_utils.py +563 -0
- agent_control_plane/interfaces/__init__.py +55 -0
- agent_control_plane/interfaces/kernel_interface.py +361 -0
- agent_control_plane/interfaces/plugin_interface.py +497 -0
- agent_control_plane/interfaces/protocol_interfaces.py +387 -0
- agent_control_plane/kernel_space.py +1009 -0
- agent_control_plane/langchain_adapter.py +424 -0
- agent_control_plane/lifecycle.py +3113 -0
- agent_control_plane/mcp_adapter.py +653 -0
- agent_control_plane/ml_safety.py +563 -0
- agent_control_plane/multimodal.py +727 -0
- agent_control_plane/mute_agent.py +422 -0
- agent_control_plane/observability.py +787 -0
- agent_control_plane/orchestrator.py +482 -0
- agent_control_plane/plugin_registry.py +750 -0
- agent_control_plane/policy_engine.py +954 -0
- agent_control_plane/process_isolation.py +777 -0
- agent_control_plane/shadow_mode.py +310 -0
- agent_control_plane/signals.py +493 -0
- agent_control_plane/supervisor_agents.py +430 -0
- agent_control_plane/time_travel_debugger.py +557 -0
- agent_control_plane/tool_registry.py +452 -0
- agent_control_plane/vfs.py +697 -0
- agent_kernel/__init__.py +69 -0
- agent_kernel/analyzer.py +435 -0
- agent_kernel/auditor.py +36 -0
- agent_kernel/completeness_auditor.py +237 -0
- agent_kernel/detector.py +203 -0
- agent_kernel/kernel.py +744 -0
- agent_kernel/memory_manager.py +85 -0
- agent_kernel/models.py +374 -0
- agent_kernel/nudge_mechanism.py +263 -0
- agent_kernel/outcome_analyzer.py +338 -0
- agent_kernel/patcher.py +582 -0
- agent_kernel/semantic_analyzer.py +316 -0
- agent_kernel/semantic_purge.py +349 -0
- agent_kernel/simulator.py +449 -0
- agent_kernel/teacher.py +85 -0
- agent_kernel/triage.py +152 -0
- agent_os/__init__.py +409 -0
- agent_os/_adversarial_impl.py +200 -0
- agent_os/_circuit_breaker_impl.py +232 -0
- agent_os/_mcp_metrics.py +193 -0
- agent_os/adversarial.py +20 -0
- agent_os/agents_compat.py +490 -0
- agent_os/audit_logger.py +135 -0
- agent_os/base_agent.py +651 -0
- agent_os/circuit_breaker.py +34 -0
- agent_os/cli/__init__.py +659 -0
- agent_os/cli/cmd_audit.py +128 -0
- agent_os/cli/cmd_init.py +152 -0
- agent_os/cli/cmd_policy.py +41 -0
- agent_os/cli/cmd_policy_gen.py +180 -0
- agent_os/cli/cmd_validate.py +258 -0
- agent_os/cli/mcp_scan.py +265 -0
- agent_os/cli/output.py +192 -0
- agent_os/cli/policy_checker.py +330 -0
- agent_os/compat.py +74 -0
- agent_os/constraint_graph.py +234 -0
- agent_os/content_governance.py +140 -0
- agent_os/context_budget.py +305 -0
- agent_os/credential_redactor.py +224 -0
- agent_os/diff_policy.py +89 -0
- agent_os/egress_policy.py +159 -0
- agent_os/escalation.py +276 -0
- agent_os/event_bus.py +124 -0
- agent_os/exceptions.py +180 -0
- agent_os/execution_context_policy.py +141 -0
- agent_os/github_enterprise.py +96 -0
- agent_os/health.py +20 -0
- agent_os/integrations/__init__.py +279 -0
- agent_os/integrations/a2a_adapter.py +279 -0
- agent_os/integrations/agent_lightning/__init__.py +30 -0
- agent_os/integrations/anthropic_adapter.py +420 -0
- agent_os/integrations/autogen_adapter.py +620 -0
- agent_os/integrations/base.py +1137 -0
- agent_os/integrations/compat.py +229 -0
- agent_os/integrations/config.py +98 -0
- agent_os/integrations/conversation_guardian.py +957 -0
- agent_os/integrations/crewai_adapter.py +467 -0
- agent_os/integrations/drift_detector.py +425 -0
- agent_os/integrations/dry_run.py +124 -0
- agent_os/integrations/escalation.py +582 -0
- agent_os/integrations/gemini_adapter.py +364 -0
- agent_os/integrations/google_adk_adapter.py +633 -0
- agent_os/integrations/guardrails_adapter.py +394 -0
- agent_os/integrations/health.py +197 -0
- agent_os/integrations/langchain_adapter.py +654 -0
- agent_os/integrations/llamafirewall.py +343 -0
- agent_os/integrations/llamaindex_adapter.py +188 -0
- agent_os/integrations/logging.py +191 -0
- agent_os/integrations/maf_adapter.py +631 -0
- agent_os/integrations/mistral_adapter.py +365 -0
- agent_os/integrations/openai_adapter.py +816 -0
- agent_os/integrations/openai_agents_sdk.py +406 -0
- agent_os/integrations/policy_compose.py +171 -0
- agent_os/integrations/profiling.py +144 -0
- agent_os/integrations/pydantic_ai_adapter.py +420 -0
- agent_os/integrations/rate_limiter.py +130 -0
- agent_os/integrations/rbac.py +143 -0
- agent_os/integrations/registry.py +113 -0
- agent_os/integrations/scope_guard.py +303 -0
- agent_os/integrations/semantic_kernel_adapter.py +769 -0
- agent_os/integrations/smolagents_adapter.py +629 -0
- agent_os/integrations/templates.py +178 -0
- agent_os/integrations/token_budget.py +134 -0
- agent_os/integrations/tool_aliases.py +190 -0
- agent_os/integrations/webhooks.py +177 -0
- agent_os/lite.py +208 -0
- agent_os/mcp_gateway.py +385 -0
- agent_os/mcp_message_signer.py +273 -0
- agent_os/mcp_protocols.py +161 -0
- agent_os/mcp_response_scanner.py +232 -0
- agent_os/mcp_security.py +924 -0
- agent_os/mcp_session_auth.py +231 -0
- agent_os/mcp_sliding_rate_limiter.py +184 -0
- agent_os/memory_guard.py +409 -0
- agent_os/metrics.py +134 -0
- agent_os/mute.py +428 -0
- agent_os/mute_agent.py +209 -0
- agent_os/policies/__init__.py +77 -0
- agent_os/policies/async_evaluator.py +275 -0
- agent_os/policies/backends.py +670 -0
- agent_os/policies/bridge.py +169 -0
- agent_os/policies/budget.py +85 -0
- agent_os/policies/cli.py +294 -0
- agent_os/policies/conflict_resolution.py +270 -0
- agent_os/policies/data_classification.py +252 -0
- agent_os/policies/evaluator.py +239 -0
- agent_os/policies/policy_schema.json +228 -0
- agent_os/policies/rate_limiting.py +145 -0
- agent_os/policies/schema.py +115 -0
- agent_os/policies/shared.py +331 -0
- agent_os/prompt_injection.py +694 -0
- agent_os/providers.py +182 -0
- agent_os/py.typed +0 -0
- agent_os/retry.py +81 -0
- agent_os/reversibility.py +251 -0
- agent_os/sandbox.py +432 -0
- agent_os/sandbox_provider.py +140 -0
- agent_os/secure_codegen.py +525 -0
- agent_os/security_skills.py +538 -0
- agent_os/semantic_policy.py +422 -0
- agent_os/server/__init__.py +15 -0
- agent_os/server/__main__.py +25 -0
- agent_os/server/app.py +277 -0
- agent_os/server/models.py +104 -0
- agent_os/shift_left_metrics.py +130 -0
- agent_os/stateless.py +742 -0
- agent_os/supervisor.py +148 -0
- agent_os/task_outcome.py +148 -0
- agent_os/transparency.py +181 -0
- agent_os/trust_root.py +128 -0
- agent_os_kernel-3.1.0.dist-info/METADATA +1269 -0
- agent_os_kernel-3.1.0.dist-info/RECORD +337 -0
- agent_os_kernel-3.1.0.dist-info/WHEEL +4 -0
- agent_os_kernel-3.1.0.dist-info/entry_points.txt +2 -0
- agent_os_kernel-3.1.0.dist-info/licenses/LICENSE +21 -0
- agent_os_observability/__init__.py +27 -0
- agent_os_observability/dashboards.py +898 -0
- agent_os_observability/metrics.py +398 -0
- agent_os_observability/server.py +223 -0
- agent_os_observability/tracer.py +232 -0
- agent_primitives/__init__.py +24 -0
- agent_primitives/failures.py +84 -0
- agent_primitives/py.typed +0 -0
- amb_core/__init__.py +177 -0
- amb_core/adapters/__init__.py +57 -0
- amb_core/adapters/aws_sqs_broker.py +376 -0
- amb_core/adapters/azure_servicebus_broker.py +340 -0
- amb_core/adapters/kafka_broker.py +260 -0
- amb_core/adapters/nats_broker.py +285 -0
- amb_core/adapters/rabbitmq_broker.py +235 -0
- amb_core/adapters/redis_broker.py +262 -0
- amb_core/broker.py +145 -0
- amb_core/bus.py +481 -0
- amb_core/cloudevents.py +509 -0
- amb_core/dlq.py +345 -0
- amb_core/hf_utils.py +536 -0
- amb_core/memory_broker.py +410 -0
- amb_core/models.py +141 -0
- amb_core/persistence.py +529 -0
- amb_core/schema.py +294 -0
- amb_core/tracing.py +358 -0
- atr/__init__.py +640 -0
- atr/access.py +348 -0
- atr/composition.py +645 -0
- atr/decorator.py +357 -0
- atr/executor.py +384 -0
- atr/health.py +557 -0
- atr/hf_utils.py +449 -0
- atr/injection.py +422 -0
- atr/metrics.py +440 -0
- atr/policies.py +403 -0
- atr/py.typed +2 -0
- atr/registry.py +452 -0
- atr/schema.py +480 -0
- atr/tools/safe/__init__.py +75 -0
- atr/tools/safe/calculator.py +467 -0
- atr/tools/safe/datetime_tool.py +443 -0
- atr/tools/safe/file_reader.py +402 -0
- atr/tools/safe/http_client.py +316 -0
- atr/tools/safe/json_parser.py +374 -0
- atr/tools/safe/text_tool.py +537 -0
- atr/tools/safe/toolkit.py +175 -0
- caas/__init__.py +162 -0
- caas/api/__init__.py +7 -0
- caas/api/server.py +1328 -0
- caas/caching.py +834 -0
- caas/cli.py +210 -0
- caas/conversation.py +223 -0
- caas/decay.py +72 -0
- caas/detection/__init__.py +9 -0
- caas/detection/detector.py +238 -0
- caas/enrichment.py +130 -0
- caas/gateway/__init__.py +27 -0
- caas/gateway/trust_gateway.py +474 -0
- caas/hf_utils.py +479 -0
- caas/ingestion/__init__.py +23 -0
- caas/ingestion/processors.py +253 -0
- caas/ingestion/structure_parser.py +188 -0
- caas/models.py +356 -0
- caas/pragmatic_truth.py +444 -0
- caas/routing/__init__.py +10 -0
- caas/routing/heuristic_router.py +58 -0
- caas/storage/__init__.py +9 -0
- caas/storage/store.py +389 -0
- caas/triad.py +213 -0
- caas/tuning/__init__.py +9 -0
- caas/tuning/tuner.py +329 -0
- caas/vfs/__init__.py +14 -0
- caas/vfs/filesystem.py +452 -0
- cmvk/__init__.py +218 -0
- cmvk/audit.py +402 -0
- cmvk/benchmarks.py +478 -0
- cmvk/constitutional.py +904 -0
- cmvk/hf_utils.py +301 -0
- cmvk/metrics.py +473 -0
- cmvk/profiles.py +300 -0
- cmvk/py.typed +0 -0
- cmvk/types.py +12 -0
- cmvk/verification.py +956 -0
- emk/__init__.py +89 -0
- emk/causal.py +352 -0
- emk/hf_utils.py +421 -0
- emk/indexer.py +83 -0
- emk/py.typed +0 -0
- emk/schema.py +204 -0
- emk/sleep_cycle.py +347 -0
- emk/store.py +281 -0
- iatp/__init__.py +166 -0
- iatp/attestation.py +461 -0
- iatp/cli.py +317 -0
- iatp/hf_utils.py +472 -0
- iatp/ipc_pipes.py +580 -0
- iatp/main.py +412 -0
- iatp/models/__init__.py +447 -0
- iatp/policy_engine.py +337 -0
- iatp/py.typed +2 -0
- iatp/recovery.py +321 -0
- iatp/security/__init__.py +270 -0
- iatp/sidecar/__init__.py +519 -0
- iatp/telemetry/__init__.py +164 -0
- iatp/tests/__init__.py +1 -0
- iatp/tests/test_attestation.py +370 -0
- iatp/tests/test_cli.py +131 -0
- iatp/tests/test_ed25519_attestation.py +211 -0
- iatp/tests/test_models.py +130 -0
- iatp/tests/test_policy_engine.py +347 -0
- iatp/tests/test_recovery.py +281 -0
- iatp/tests/test_security.py +222 -0
- iatp/tests/test_sidecar.py +167 -0
- iatp/tests/test_telemetry.py +175 -0
- mcp_kernel_server/__init__.py +28 -0
- mcp_kernel_server/cli.py +274 -0
- mcp_kernel_server/resources.py +217 -0
- mcp_kernel_server/server.py +564 -0
- mcp_kernel_server/tools.py +1174 -0
- mute_agent/__init__.py +68 -0
- mute_agent/core/__init__.py +1 -0
- mute_agent/core/execution_agent.py +166 -0
- mute_agent/core/handshake_protocol.py +201 -0
- mute_agent/core/reasoning_agent.py +238 -0
- mute_agent/knowledge_graph/__init__.py +1 -0
- mute_agent/knowledge_graph/graph_elements.py +65 -0
- mute_agent/knowledge_graph/multidimensional_graph.py +170 -0
- mute_agent/knowledge_graph/subgraph.py +224 -0
- mute_agent/listener/__init__.py +43 -0
- mute_agent/listener/adapters/__init__.py +31 -0
- mute_agent/listener/adapters/base_adapter.py +189 -0
- mute_agent/listener/adapters/caas_adapter.py +344 -0
- mute_agent/listener/adapters/control_plane_adapter.py +436 -0
- mute_agent/listener/adapters/iatp_adapter.py +332 -0
- mute_agent/listener/adapters/scak_adapter.py +251 -0
- mute_agent/listener/listener.py +610 -0
- mute_agent/listener/state_observer.py +436 -0
- mute_agent/listener/threshold_config.py +313 -0
- mute_agent/super_system/__init__.py +1 -0
- mute_agent/super_system/router.py +204 -0
- mute_agent/visualization/__init__.py +10 -0
- mute_agent/visualization/graph_debugger.py +502 -0
- nexus/README.md +60 -0
- nexus/__init__.py +51 -0
- nexus/arbiter.py +359 -0
- nexus/client.py +466 -0
- nexus/dmz.py +444 -0
- nexus/escrow.py +430 -0
- nexus/exceptions.py +286 -0
- nexus/pyproject.toml +36 -0
- nexus/registry.py +393 -0
- nexus/reputation.py +425 -0
- nexus/schemas/__init__.py +51 -0
- nexus/schemas/compliance.py +276 -0
- nexus/schemas/escrow.py +251 -0
- nexus/schemas/manifest.py +225 -0
- nexus/schemas/receipt.py +208 -0
- nexus/tests/__init__.py +0 -0
- nexus/tests/conftest.py +146 -0
- nexus/tests/test_arbiter.py +192 -0
- nexus/tests/test_dmz.py +194 -0
- nexus/tests/test_escrow.py +276 -0
- nexus/tests/test_exceptions.py +225 -0
- nexus/tests/test_registry.py +232 -0
- nexus/tests/test_reputation.py +328 -0
- nexus/tests/test_schemas.py +295 -0
|
@@ -0,0 +1,653 @@
|
|
|
1
|
+
# Copyright (c) Microsoft Corporation.
|
|
2
|
+
# Licensed under the MIT License.
|
|
3
|
+
"""
|
|
4
|
+
MCP (Model Context Protocol) Adapter - Agent Control Plane Integration
|
|
5
|
+
|
|
6
|
+
This adapter provides governance for MCP-compliant tool and resource servers.
|
|
7
|
+
MCP is Anthropic's open standard for connecting AI agents to external tools,
|
|
8
|
+
data sources, and services.
|
|
9
|
+
|
|
10
|
+
The MCP adapter intercepts MCP protocol messages (tools/call, resources/read, etc.)
|
|
11
|
+
and applies Agent Control Plane governance before allowing execution.
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
from agent_control_plane import AgentControlPlane
|
|
15
|
+
from agent_control_plane.mcp_adapter import MCPAdapter, MCPServer
|
|
16
|
+
|
|
17
|
+
# Setup control plane
|
|
18
|
+
control_plane = AgentControlPlane()
|
|
19
|
+
agent_context = control_plane.create_agent("my-agent", permissions)
|
|
20
|
+
|
|
21
|
+
# Create governed MCP server
|
|
22
|
+
mcp_server = MCPServer(
|
|
23
|
+
server_name="file-server",
|
|
24
|
+
transport="stdio",
|
|
25
|
+
control_plane=control_plane,
|
|
26
|
+
agent_context=agent_context
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Register tools
|
|
30
|
+
mcp_server.register_tool("read_file", handle_read_file)
|
|
31
|
+
mcp_server.register_resource("file://", handle_file_resource)
|
|
32
|
+
|
|
33
|
+
# All MCP calls are now governed!
|
|
34
|
+
mcp_server.start()
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
from typing import Any, Dict, List, Optional, Callable, Union
|
|
38
|
+
import json
|
|
39
|
+
import logging
|
|
40
|
+
from datetime import datetime
|
|
41
|
+
from enum import Enum
|
|
42
|
+
|
|
43
|
+
from .agent_kernel import ActionType, AgentContext
|
|
44
|
+
from .control_plane import AgentControlPlane
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class MCPMessageType(Enum):
|
|
48
|
+
"""MCP protocol message types.
|
|
49
|
+
|
|
50
|
+
Enumerates the JSON-RPC methods defined by the Model Context Protocol
|
|
51
|
+
specification. Each value corresponds to a method string sent in the
|
|
52
|
+
``"method"`` field of an MCP JSON-RPC 2.0 request.
|
|
53
|
+
|
|
54
|
+
Attributes:
|
|
55
|
+
TOOLS_LIST: List available tools on the server.
|
|
56
|
+
TOOLS_CALL: Invoke a registered tool by name.
|
|
57
|
+
RESOURCES_LIST: List available resources (files, databases, etc.).
|
|
58
|
+
RESOURCES_READ: Read the contents of a specific resource URI.
|
|
59
|
+
PROMPTS_LIST: List available prompt templates.
|
|
60
|
+
PROMPTS_GET: Retrieve a specific prompt template by name.
|
|
61
|
+
COMPLETION: Request a completion (reserved for future use).
|
|
62
|
+
|
|
63
|
+
Example:
|
|
64
|
+
>>> msg_type = MCPMessageType.TOOLS_CALL
|
|
65
|
+
>>> msg_type.value
|
|
66
|
+
'tools/call'
|
|
67
|
+
"""
|
|
68
|
+
TOOLS_LIST = "tools/list"
|
|
69
|
+
TOOLS_CALL = "tools/call"
|
|
70
|
+
RESOURCES_LIST = "resources/list"
|
|
71
|
+
RESOURCES_READ = "resources/read"
|
|
72
|
+
PROMPTS_LIST = "prompts/list"
|
|
73
|
+
PROMPTS_GET = "prompts/get"
|
|
74
|
+
COMPLETION = "completion/complete"
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# Mapping from MCP operations to ActionTypes
|
|
78
|
+
DEFAULT_MCP_MAPPING = {
|
|
79
|
+
# Tool operations
|
|
80
|
+
"tools/call": ActionType.CODE_EXECUTION, # Default for tool calls
|
|
81
|
+
|
|
82
|
+
# Resource operations
|
|
83
|
+
"resources/read": ActionType.FILE_READ, # Default for resource reads
|
|
84
|
+
"resources/write": ActionType.FILE_WRITE, # If write operations exist
|
|
85
|
+
|
|
86
|
+
# Specific tool patterns
|
|
87
|
+
"file_read": ActionType.FILE_READ,
|
|
88
|
+
"file_write": ActionType.FILE_WRITE,
|
|
89
|
+
"database_query": ActionType.DATABASE_QUERY,
|
|
90
|
+
"database_write": ActionType.DATABASE_WRITE,
|
|
91
|
+
"api_call": ActionType.API_CALL,
|
|
92
|
+
"http_request": ActionType.API_CALL,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class MCPAdapter:
|
|
97
|
+
"""MCP Protocol Adapter with Agent Control Plane Governance.
|
|
98
|
+
|
|
99
|
+
Intercepts MCP protocol messages and applies governance rules before
|
|
100
|
+
forwarding to the actual MCP server or client. MCP uses JSON-RPC 2.0
|
|
101
|
+
for communication, with specific methods like:
|
|
102
|
+
|
|
103
|
+
- ``tools/list``: List available tools
|
|
104
|
+
- ``tools/call``: Execute a tool
|
|
105
|
+
- ``resources/list``: List available resources
|
|
106
|
+
- ``resources/read``: Read a resource
|
|
107
|
+
|
|
108
|
+
The adapter ensures all operations respect agent permissions and
|
|
109
|
+
policies defined in the control plane. Unknown tools are denied by
|
|
110
|
+
default (secure-by-default).
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
control_plane: The ``AgentControlPlane`` instance for governance.
|
|
114
|
+
agent_context: The ``AgentContext`` for the agent using this adapter.
|
|
115
|
+
mcp_handler: Optional upstream MCP message handler to delegate to
|
|
116
|
+
after governance checks pass.
|
|
117
|
+
tool_mapping: Optional custom mapping from tool names to
|
|
118
|
+
``ActionType`` values. Merged with ``DEFAULT_MCP_MAPPING``.
|
|
119
|
+
on_block: Optional callback invoked when an action is blocked.
|
|
120
|
+
Receives ``(tool_name, arguments, check_result)``.
|
|
121
|
+
logger: Optional logger instance.
|
|
122
|
+
|
|
123
|
+
Attributes:
|
|
124
|
+
registered_tools: Dictionary of tool name to tool metadata.
|
|
125
|
+
registered_resources: Dictionary of URI pattern to resource metadata.
|
|
126
|
+
tool_mapping: Combined mapping of tool/operation names to
|
|
127
|
+
``ActionType`` values used for governance decisions.
|
|
128
|
+
|
|
129
|
+
Example:
|
|
130
|
+
>>> from agent_control_plane import AgentControlPlane
|
|
131
|
+
>>> from agent_control_plane.mcp_adapter import MCPAdapter
|
|
132
|
+
>>>
|
|
133
|
+
>>> cp = AgentControlPlane()
|
|
134
|
+
>>> ctx = cp.create_agent("my-agent")
|
|
135
|
+
>>> adapter = MCPAdapter(control_plane=cp, agent_context=ctx)
|
|
136
|
+
>>>
|
|
137
|
+
>>> # Register a tool
|
|
138
|
+
>>> adapter.register_tool("read_file", {
|
|
139
|
+
... "name": "read_file",
|
|
140
|
+
... "description": "Read a file from disk",
|
|
141
|
+
... "inputSchema": {"type": "object", "properties": {"path": {"type": "string"}}}
|
|
142
|
+
... })
|
|
143
|
+
>>>
|
|
144
|
+
>>> # Handle an MCP request — governance is applied automatically
|
|
145
|
+
>>> response = adapter.handle_message({
|
|
146
|
+
... "jsonrpc": "2.0",
|
|
147
|
+
... "id": 1,
|
|
148
|
+
... "method": "tools/call",
|
|
149
|
+
... "params": {"name": "read_file", "arguments": {"path": "/tmp/data.txt"}}
|
|
150
|
+
... })
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
def __init__(
|
|
154
|
+
self,
|
|
155
|
+
control_plane: AgentControlPlane,
|
|
156
|
+
agent_context: AgentContext,
|
|
157
|
+
mcp_handler: Optional[Any] = None,
|
|
158
|
+
tool_mapping: Optional[Dict[str, ActionType]] = None,
|
|
159
|
+
on_block: Optional[Callable[[str, Dict, Dict], None]] = None,
|
|
160
|
+
logger: Optional[logging.Logger] = None
|
|
161
|
+
):
|
|
162
|
+
"""
|
|
163
|
+
Initialize the MCP adapter.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
control_plane: The AgentControlPlane instance for governance
|
|
167
|
+
agent_context: The AgentContext for the agent using this adapter
|
|
168
|
+
mcp_handler: Optional MCP message handler to wrap
|
|
169
|
+
tool_mapping: Optional custom mapping from tool names to ActionTypes
|
|
170
|
+
on_block: Optional callback when an action is blocked
|
|
171
|
+
logger: Optional logger instance
|
|
172
|
+
"""
|
|
173
|
+
self.control_plane = control_plane
|
|
174
|
+
self.agent_context = agent_context
|
|
175
|
+
self.mcp_handler = mcp_handler
|
|
176
|
+
self.logger = logger or logging.getLogger("MCPAdapter")
|
|
177
|
+
self.on_block = on_block
|
|
178
|
+
|
|
179
|
+
# Merge default mapping with custom mapping
|
|
180
|
+
self.tool_mapping = DEFAULT_MCP_MAPPING.copy()
|
|
181
|
+
if tool_mapping:
|
|
182
|
+
self.tool_mapping.update({k.lower(): v for k, v in tool_mapping.items()})
|
|
183
|
+
|
|
184
|
+
# Register available tools and resources
|
|
185
|
+
self.registered_tools: Dict[str, Dict] = {}
|
|
186
|
+
self.registered_resources: Dict[str, Dict] = {}
|
|
187
|
+
|
|
188
|
+
self.logger.info(
|
|
189
|
+
f"Initialized MCPAdapter for agent {agent_context.agent_id}"
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
def handle_message(self, message: Dict[str, Any]) -> Dict[str, Any]:
|
|
193
|
+
"""Handle an MCP protocol message with governance.
|
|
194
|
+
|
|
195
|
+
This is the main entry point for MCP messages. It parses the
|
|
196
|
+
JSON-RPC message, applies governance checks via the control plane,
|
|
197
|
+
and returns the result.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
message: MCP JSON-RPC 2.0 message containing ``jsonrpc``,
|
|
201
|
+
``method``, ``params``, and ``id`` fields.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
A JSON-RPC 2.0 response dict. On success, contains a
|
|
205
|
+
``"result"`` key. On failure (governance block or error),
|
|
206
|
+
contains an ``"error"`` key with ``"code"`` and ``"message"``.
|
|
207
|
+
|
|
208
|
+
Raises:
|
|
209
|
+
PermissionError: Internally raised when governance blocks an
|
|
210
|
+
action; caught and converted to a JSON-RPC error response.
|
|
211
|
+
"""
|
|
212
|
+
# Parse the JSON-RPC message
|
|
213
|
+
jsonrpc = message.get("jsonrpc", "2.0")
|
|
214
|
+
method = message.get("method", "")
|
|
215
|
+
params = message.get("params", {})
|
|
216
|
+
msg_id = message.get("id")
|
|
217
|
+
|
|
218
|
+
self.logger.debug(f"Received MCP message: method={method}, id={msg_id}")
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
# Route to appropriate handler based on method
|
|
222
|
+
if method == MCPMessageType.TOOLS_LIST.value:
|
|
223
|
+
result = self._handle_tools_list(params)
|
|
224
|
+
elif method == MCPMessageType.TOOLS_CALL.value:
|
|
225
|
+
result = self._handle_tools_call(params)
|
|
226
|
+
elif method == MCPMessageType.RESOURCES_LIST.value:
|
|
227
|
+
result = self._handle_resources_list(params)
|
|
228
|
+
elif method == MCPMessageType.RESOURCES_READ.value:
|
|
229
|
+
result = self._handle_resources_read(params)
|
|
230
|
+
elif method == MCPMessageType.PROMPTS_LIST.value:
|
|
231
|
+
result = self._handle_prompts_list(params)
|
|
232
|
+
elif method == MCPMessageType.PROMPTS_GET.value:
|
|
233
|
+
result = self._handle_prompts_get(params)
|
|
234
|
+
else:
|
|
235
|
+
# Unknown method
|
|
236
|
+
return self._create_error_response(msg_id, -32601, f"Method not found: {method}")
|
|
237
|
+
|
|
238
|
+
# Success response
|
|
239
|
+
return {
|
|
240
|
+
"jsonrpc": jsonrpc,
|
|
241
|
+
"id": msg_id,
|
|
242
|
+
"result": result
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
except PermissionError as e:
|
|
246
|
+
# Governance blocked the action
|
|
247
|
+
self.logger.warning(f"Permission denied: {str(e)}")
|
|
248
|
+
return self._create_error_response(msg_id, -32000, str(e))
|
|
249
|
+
|
|
250
|
+
except Exception as e:
|
|
251
|
+
# Other errors
|
|
252
|
+
self.logger.error(f"Error handling MCP message: {str(e)}")
|
|
253
|
+
return self._create_error_response(msg_id, -32603, f"Internal error: {str(e)}")
|
|
254
|
+
|
|
255
|
+
def _handle_tools_list(self, params: Dict) -> Dict:
|
|
256
|
+
"""Handle tools/list - return list of available tools."""
|
|
257
|
+
# Return only tools that the agent has permission to use
|
|
258
|
+
allowed_tools = []
|
|
259
|
+
|
|
260
|
+
for tool_name, tool_info in self.registered_tools.items():
|
|
261
|
+
action_type = self._map_tool_to_action(tool_name)
|
|
262
|
+
if action_type and self._check_permission(action_type, {}):
|
|
263
|
+
allowed_tools.append(tool_info)
|
|
264
|
+
|
|
265
|
+
return {"tools": allowed_tools}
|
|
266
|
+
|
|
267
|
+
def _handle_tools_call(self, params: Dict) -> Dict:
|
|
268
|
+
"""Handle tools/call — execute a tool with governance.
|
|
269
|
+
|
|
270
|
+
Maps the tool name to an ``ActionType``, checks permissions via
|
|
271
|
+
the control plane, and either delegates to the registered handler
|
|
272
|
+
or returns the control plane result.
|
|
273
|
+
|
|
274
|
+
Args:
|
|
275
|
+
params: JSON-RPC params containing ``"name"`` and ``"arguments"``.
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
Tool execution result dict with MCP ``content`` format.
|
|
279
|
+
|
|
280
|
+
Raises:
|
|
281
|
+
PermissionError: If the tool is unknown or governance denies
|
|
282
|
+
the action.
|
|
283
|
+
"""
|
|
284
|
+
tool_name = params.get("name", "")
|
|
285
|
+
arguments = params.get("arguments", {})
|
|
286
|
+
|
|
287
|
+
self.logger.info(f"Tool call request: {tool_name}")
|
|
288
|
+
|
|
289
|
+
# Map to ActionType
|
|
290
|
+
action_type = self._map_tool_to_action(tool_name)
|
|
291
|
+
|
|
292
|
+
if action_type is None:
|
|
293
|
+
# Security: Unknown tools are denied by default
|
|
294
|
+
self.logger.warning(f"Unknown tool '{tool_name}', denying by default")
|
|
295
|
+
raise PermissionError(f"Unknown tool: {tool_name}. Tool must be mapped to an ActionType.")
|
|
296
|
+
|
|
297
|
+
# THE KERNEL CHECK - This is where governance happens
|
|
298
|
+
check_result = self.control_plane.execute_action(
|
|
299
|
+
self.agent_context,
|
|
300
|
+
action_type,
|
|
301
|
+
arguments
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
if not check_result['success']:
|
|
305
|
+
# Action is BLOCKED
|
|
306
|
+
error_msg = f"Tool call blocked: {check_result.get('error', 'Policy violation')}"
|
|
307
|
+
self.logger.warning(f"BLOCKED: {tool_name} - {error_msg}")
|
|
308
|
+
|
|
309
|
+
if self.on_block:
|
|
310
|
+
self.on_block(tool_name, arguments, check_result)
|
|
311
|
+
|
|
312
|
+
raise PermissionError(error_msg)
|
|
313
|
+
|
|
314
|
+
self.logger.info(f"ALLOWED: {tool_name}")
|
|
315
|
+
|
|
316
|
+
# If we have a handler, delegate to it
|
|
317
|
+
if self.mcp_handler and hasattr(self.mcp_handler, 'call_tool'):
|
|
318
|
+
return self.mcp_handler.call_tool(tool_name, arguments)
|
|
319
|
+
|
|
320
|
+
# Otherwise return the result from the control plane
|
|
321
|
+
return {
|
|
322
|
+
"content": [{
|
|
323
|
+
"type": "text",
|
|
324
|
+
"text": json.dumps(check_result.get('result', {}))
|
|
325
|
+
}]
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
def _handle_resources_list(self, params: Dict) -> Dict:
|
|
329
|
+
"""Handle resources/list - return list of available resources."""
|
|
330
|
+
# Return only resources the agent can access
|
|
331
|
+
allowed_resources = []
|
|
332
|
+
|
|
333
|
+
for resource_uri, resource_info in self.registered_resources.items():
|
|
334
|
+
# Determine appropriate action type for this resource
|
|
335
|
+
action_type = self._map_resource_to_action(resource_uri)
|
|
336
|
+
|
|
337
|
+
# Check permission for this resource
|
|
338
|
+
if self._check_permission(action_type, {}):
|
|
339
|
+
allowed_resources.append(resource_info)
|
|
340
|
+
|
|
341
|
+
return {"resources": allowed_resources}
|
|
342
|
+
|
|
343
|
+
def _handle_resources_read(self, params: Dict) -> Dict:
|
|
344
|
+
"""Handle resources/read — read a resource with governance.
|
|
345
|
+
|
|
346
|
+
Determines the ``ActionType`` from the URI scheme and checks
|
|
347
|
+
permissions before returning resource contents.
|
|
348
|
+
|
|
349
|
+
Args:
|
|
350
|
+
params: JSON-RPC params containing ``"uri"``.
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
Resource contents dict with MCP ``contents`` format.
|
|
354
|
+
|
|
355
|
+
Raises:
|
|
356
|
+
PermissionError: If governance denies the resource read.
|
|
357
|
+
"""
|
|
358
|
+
uri = params.get("uri", "")
|
|
359
|
+
|
|
360
|
+
self.logger.info(f"Resource read request: {uri}")
|
|
361
|
+
|
|
362
|
+
# Determine action type based on URI scheme
|
|
363
|
+
action_type = self._map_resource_to_action(uri)
|
|
364
|
+
|
|
365
|
+
# Check permission
|
|
366
|
+
check_result = self.control_plane.execute_action(
|
|
367
|
+
self.agent_context,
|
|
368
|
+
action_type,
|
|
369
|
+
{"uri": uri}
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
if not check_result['success']:
|
|
373
|
+
error_msg = f"Resource read blocked: {check_result.get('error', 'Policy violation')}"
|
|
374
|
+
self.logger.warning(f"BLOCKED: {uri} - {error_msg}")
|
|
375
|
+
|
|
376
|
+
if self.on_block:
|
|
377
|
+
self.on_block(uri, {"uri": uri}, check_result)
|
|
378
|
+
|
|
379
|
+
raise PermissionError(error_msg)
|
|
380
|
+
|
|
381
|
+
self.logger.info(f"ALLOWED: resource read {uri}")
|
|
382
|
+
|
|
383
|
+
# If we have a handler, delegate to it
|
|
384
|
+
if self.mcp_handler and hasattr(self.mcp_handler, 'read_resource'):
|
|
385
|
+
return self.mcp_handler.read_resource(uri)
|
|
386
|
+
|
|
387
|
+
# Otherwise return a placeholder
|
|
388
|
+
return {
|
|
389
|
+
"contents": [{
|
|
390
|
+
"uri": uri,
|
|
391
|
+
"mimeType": "text/plain",
|
|
392
|
+
"text": json.dumps(check_result.get('result', {}))
|
|
393
|
+
}]
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
def _handle_prompts_list(self, params: Dict) -> Dict:
|
|
397
|
+
"""
|
|
398
|
+
Handle prompts/list - list available prompts.
|
|
399
|
+
|
|
400
|
+
TODO: Implement actual prompt management when needed.
|
|
401
|
+
"""
|
|
402
|
+
# Prompts are generally safe to list
|
|
403
|
+
return {"prompts": []}
|
|
404
|
+
|
|
405
|
+
def _handle_prompts_get(self, params: Dict) -> Dict:
|
|
406
|
+
"""
|
|
407
|
+
Handle prompts/get - get a specific prompt.
|
|
408
|
+
|
|
409
|
+
TODO: Implement actual prompt retrieval when needed.
|
|
410
|
+
"""
|
|
411
|
+
# Prompts are generally safe to retrieve
|
|
412
|
+
prompt_name = params.get("name", "")
|
|
413
|
+
return {
|
|
414
|
+
"messages": [],
|
|
415
|
+
"description": f"Prompt: {prompt_name}"
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
def _map_tool_to_action(self, tool_name: str) -> Optional[ActionType]:
|
|
419
|
+
"""Map an MCP tool name to an ``ActionType``.
|
|
420
|
+
|
|
421
|
+
Resolution order:
|
|
422
|
+
1. Exact match in ``self.tool_mapping`` (case-insensitive).
|
|
423
|
+
2. Pattern-based heuristics (e.g. names containing ``"read"``
|
|
424
|
+
and ``"file"`` map to ``FILE_READ``).
|
|
425
|
+
3. Returns ``None`` for unrecognized tools (deny-by-default).
|
|
426
|
+
|
|
427
|
+
Args:
|
|
428
|
+
tool_name: The MCP tool name to resolve.
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
The corresponding ``ActionType``, or ``None`` if the tool
|
|
432
|
+
cannot be mapped (triggering a denial).
|
|
433
|
+
"""
|
|
434
|
+
tool_name_lower = tool_name.lower()
|
|
435
|
+
|
|
436
|
+
# Check exact match
|
|
437
|
+
if tool_name_lower in self.tool_mapping:
|
|
438
|
+
return self.tool_mapping[tool_name_lower]
|
|
439
|
+
|
|
440
|
+
# Pattern matching
|
|
441
|
+
if any(p in tool_name_lower for p in ['read', 'get', 'fetch', 'load']) and \
|
|
442
|
+
any(p in tool_name_lower for p in ['file', 'document']):
|
|
443
|
+
return ActionType.FILE_READ
|
|
444
|
+
|
|
445
|
+
if any(p in tool_name_lower for p in ['write', 'save', 'create', 'update']) and \
|
|
446
|
+
any(p in tool_name_lower for p in ['file', 'document']):
|
|
447
|
+
return ActionType.FILE_WRITE
|
|
448
|
+
|
|
449
|
+
if any(p in tool_name_lower for p in ['sql', 'query', 'database', 'db']):
|
|
450
|
+
if any(p in tool_name_lower for p in ['insert', 'update', 'delete', 'drop']):
|
|
451
|
+
return ActionType.DATABASE_WRITE
|
|
452
|
+
return ActionType.DATABASE_QUERY
|
|
453
|
+
|
|
454
|
+
if any(p in tool_name_lower for p in ['api', 'http', 'request']):
|
|
455
|
+
return ActionType.API_CALL
|
|
456
|
+
|
|
457
|
+
if any(p in tool_name_lower for p in ['exec', 'run', 'execute', 'code', 'python', 'bash']):
|
|
458
|
+
return ActionType.CODE_EXECUTION
|
|
459
|
+
|
|
460
|
+
# Security: Return None for unknown tools (deny by default)
|
|
461
|
+
return None
|
|
462
|
+
|
|
463
|
+
def _map_resource_to_action(self, uri: str) -> ActionType:
|
|
464
|
+
"""Map a resource URI to an ActionType."""
|
|
465
|
+
if uri.startswith("file://"):
|
|
466
|
+
return ActionType.FILE_READ
|
|
467
|
+
elif uri.startswith("db://") or uri.startswith("postgres://") or uri.startswith("mysql://"):
|
|
468
|
+
return ActionType.DATABASE_QUERY
|
|
469
|
+
elif uri.startswith("http://") or uri.startswith("https://"):
|
|
470
|
+
return ActionType.API_CALL
|
|
471
|
+
else:
|
|
472
|
+
return ActionType.FILE_READ
|
|
473
|
+
|
|
474
|
+
def _check_permission(self, action_type: ActionType, parameters: Dict) -> bool:
|
|
475
|
+
"""Check if the agent has permission for an action."""
|
|
476
|
+
check_result = self.control_plane.execute_action(
|
|
477
|
+
self.agent_context,
|
|
478
|
+
action_type,
|
|
479
|
+
parameters
|
|
480
|
+
)
|
|
481
|
+
return check_result['success']
|
|
482
|
+
|
|
483
|
+
def _create_error_response(self, msg_id: Any, code: int, message: str) -> Dict:
|
|
484
|
+
"""Create a JSON-RPC error response."""
|
|
485
|
+
return {
|
|
486
|
+
"jsonrpc": "2.0",
|
|
487
|
+
"id": msg_id,
|
|
488
|
+
"error": {
|
|
489
|
+
"code": code,
|
|
490
|
+
"message": message
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
def register_tool(self, tool_name: str, tool_info: Dict):
|
|
495
|
+
"""
|
|
496
|
+
Register an MCP tool.
|
|
497
|
+
|
|
498
|
+
Args:
|
|
499
|
+
tool_name: Name of the tool
|
|
500
|
+
tool_info: Tool metadata (description, input schema, etc.)
|
|
501
|
+
"""
|
|
502
|
+
self.registered_tools[tool_name] = tool_info
|
|
503
|
+
self.logger.debug(f"Registered MCP tool: {tool_name}")
|
|
504
|
+
|
|
505
|
+
def register_resource(self, uri_pattern: str, resource_info: Dict):
|
|
506
|
+
"""
|
|
507
|
+
Register an MCP resource.
|
|
508
|
+
|
|
509
|
+
Args:
|
|
510
|
+
uri_pattern: URI pattern (e.g., "file://", "db://")
|
|
511
|
+
resource_info: Resource metadata
|
|
512
|
+
"""
|
|
513
|
+
self.registered_resources[uri_pattern] = resource_info
|
|
514
|
+
self.logger.debug(f"Registered MCP resource: {uri_pattern}")
|
|
515
|
+
|
|
516
|
+
def add_tool_mapping(self, tool_name: str, action_type: ActionType):
|
|
517
|
+
"""Add a custom tool to ActionType mapping."""
|
|
518
|
+
self.tool_mapping[tool_name.lower()] = action_type
|
|
519
|
+
self.logger.debug(f"Added MCP tool mapping: {tool_name} -> {action_type.value}")
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
class MCPServer:
|
|
523
|
+
"""Simplified MCP Server with built-in governance.
|
|
524
|
+
|
|
525
|
+
Provides a high-level API for creating an MCP-compliant server with
|
|
526
|
+
Agent Control Plane governance built in. Wraps an ``MCPAdapter``
|
|
527
|
+
internally and exposes convenience methods for tool and resource
|
|
528
|
+
registration.
|
|
529
|
+
|
|
530
|
+
Args:
|
|
531
|
+
server_name: Human-readable name for this MCP server.
|
|
532
|
+
control_plane: ``AgentControlPlane`` instance for governance.
|
|
533
|
+
agent_context: ``AgentContext`` representing the server's agent.
|
|
534
|
+
transport: Transport method — ``"stdio"`` (default) or ``"sse"``.
|
|
535
|
+
logger: Optional logger instance.
|
|
536
|
+
|
|
537
|
+
Attributes:
|
|
538
|
+
adapter: The underlying ``MCPAdapter`` that handles governance.
|
|
539
|
+
server_name: Name of this server.
|
|
540
|
+
transport: Active transport method.
|
|
541
|
+
|
|
542
|
+
Example:
|
|
543
|
+
>>> from agent_control_plane import AgentControlPlane
|
|
544
|
+
>>> from agent_control_plane.mcp_adapter import MCPServer
|
|
545
|
+
>>>
|
|
546
|
+
>>> cp = AgentControlPlane()
|
|
547
|
+
>>> ctx = cp.create_agent("file-agent")
|
|
548
|
+
>>> server = MCPServer("file-server", cp, ctx, transport="stdio")
|
|
549
|
+
>>>
|
|
550
|
+
>>> server.register_tool("read_file", handle_read, "Read a file")
|
|
551
|
+
>>> server.register_resource("file://", handle_resource, "File resources")
|
|
552
|
+
>>> server.start() # All calls are now governed
|
|
553
|
+
"""
|
|
554
|
+
|
|
555
|
+
def __init__(
|
|
556
|
+
self,
|
|
557
|
+
server_name: str,
|
|
558
|
+
control_plane: AgentControlPlane,
|
|
559
|
+
agent_context: AgentContext,
|
|
560
|
+
transport: str = "stdio",
|
|
561
|
+
logger: Optional[logging.Logger] = None
|
|
562
|
+
):
|
|
563
|
+
"""
|
|
564
|
+
Initialize an MCP server.
|
|
565
|
+
|
|
566
|
+
Args:
|
|
567
|
+
server_name: Name of the MCP server
|
|
568
|
+
control_plane: Agent Control Plane instance
|
|
569
|
+
agent_context: Agent context
|
|
570
|
+
transport: Transport method ("stdio" or "sse")
|
|
571
|
+
logger: Optional logger
|
|
572
|
+
"""
|
|
573
|
+
self.server_name = server_name
|
|
574
|
+
self.transport = transport
|
|
575
|
+
self.logger = logger or logging.getLogger(f"MCPServer.{server_name}")
|
|
576
|
+
|
|
577
|
+
# Create the adapter
|
|
578
|
+
self.adapter = MCPAdapter(
|
|
579
|
+
control_plane=control_plane,
|
|
580
|
+
agent_context=agent_context,
|
|
581
|
+
logger=self.logger
|
|
582
|
+
)
|
|
583
|
+
|
|
584
|
+
self.logger.info(f"Initialized MCP server: {server_name}")
|
|
585
|
+
|
|
586
|
+
def register_tool(self, tool_name: str, handler: Callable, description: str = ""):
|
|
587
|
+
"""Register a tool with the server."""
|
|
588
|
+
tool_info = {
|
|
589
|
+
"name": tool_name,
|
|
590
|
+
"description": description,
|
|
591
|
+
"inputSchema": {
|
|
592
|
+
"type": "object",
|
|
593
|
+
"properties": {}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
self.adapter.register_tool(tool_name, tool_info)
|
|
597
|
+
|
|
598
|
+
def register_resource(self, uri_pattern: str, handler: Callable, description: str = ""):
|
|
599
|
+
"""Register a resource with the server."""
|
|
600
|
+
resource_info = {
|
|
601
|
+
"uri": uri_pattern,
|
|
602
|
+
"name": uri_pattern,
|
|
603
|
+
"description": description,
|
|
604
|
+
"mimeType": "text/plain"
|
|
605
|
+
}
|
|
606
|
+
self.adapter.register_resource(uri_pattern, resource_info)
|
|
607
|
+
|
|
608
|
+
def handle_request(self, request: Dict) -> Dict:
|
|
609
|
+
"""Handle an MCP request."""
|
|
610
|
+
return self.adapter.handle_message(request)
|
|
611
|
+
|
|
612
|
+
def start(self):
|
|
613
|
+
"""
|
|
614
|
+
Start the MCP server (placeholder for actual implementation).
|
|
615
|
+
|
|
616
|
+
Note: This is a simplified server implementation. For production use,
|
|
617
|
+
you would need to implement:
|
|
618
|
+
- Actual transport handling (stdio, SSE, HTTP)
|
|
619
|
+
- Request/response queuing
|
|
620
|
+
- Connection management
|
|
621
|
+
- Error recovery
|
|
622
|
+
"""
|
|
623
|
+
self.logger.info(f"MCP server '{self.server_name}' started on {self.transport}")
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
def create_governed_mcp_server(
|
|
627
|
+
control_plane: AgentControlPlane,
|
|
628
|
+
agent_id: str,
|
|
629
|
+
server_name: str,
|
|
630
|
+
permissions: Optional[Dict[ActionType, Any]] = None,
|
|
631
|
+
transport: str = "stdio"
|
|
632
|
+
) -> MCPServer:
|
|
633
|
+
"""
|
|
634
|
+
Convenience function to create a governed MCP server.
|
|
635
|
+
|
|
636
|
+
Args:
|
|
637
|
+
control_plane: Agent Control Plane instance
|
|
638
|
+
agent_id: Agent ID
|
|
639
|
+
server_name: Name for the MCP server
|
|
640
|
+
permissions: Optional agent permissions
|
|
641
|
+
transport: Transport method ("stdio" or "sse")
|
|
642
|
+
|
|
643
|
+
Returns:
|
|
644
|
+
A governed MCPServer instance
|
|
645
|
+
"""
|
|
646
|
+
agent_context = control_plane.create_agent(agent_id, permissions)
|
|
647
|
+
|
|
648
|
+
return MCPServer(
|
|
649
|
+
server_name=server_name,
|
|
650
|
+
control_plane=control_plane,
|
|
651
|
+
agent_context=agent_context,
|
|
652
|
+
transport=transport
|
|
653
|
+
)
|