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.
Files changed (337) hide show
  1. agent_control_plane/__init__.py +662 -0
  2. agent_control_plane/a2a_adapter.py +543 -0
  3. agent_control_plane/adapter.py +417 -0
  4. agent_control_plane/agent_hibernation.py +394 -0
  5. agent_control_plane/agent_kernel.py +470 -0
  6. agent_control_plane/compliance.py +720 -0
  7. agent_control_plane/constraint_graphs.py +478 -0
  8. agent_control_plane/control_plane.py +854 -0
  9. agent_control_plane/example_executors.py +195 -0
  10. agent_control_plane/execution_engine.py +231 -0
  11. agent_control_plane/flight_recorder.py +846 -0
  12. agent_control_plane/governance_layer.py +435 -0
  13. agent_control_plane/hf_utils.py +563 -0
  14. agent_control_plane/interfaces/__init__.py +55 -0
  15. agent_control_plane/interfaces/kernel_interface.py +361 -0
  16. agent_control_plane/interfaces/plugin_interface.py +497 -0
  17. agent_control_plane/interfaces/protocol_interfaces.py +387 -0
  18. agent_control_plane/kernel_space.py +1009 -0
  19. agent_control_plane/langchain_adapter.py +424 -0
  20. agent_control_plane/lifecycle.py +3113 -0
  21. agent_control_plane/mcp_adapter.py +653 -0
  22. agent_control_plane/ml_safety.py +563 -0
  23. agent_control_plane/multimodal.py +727 -0
  24. agent_control_plane/mute_agent.py +422 -0
  25. agent_control_plane/observability.py +787 -0
  26. agent_control_plane/orchestrator.py +482 -0
  27. agent_control_plane/plugin_registry.py +750 -0
  28. agent_control_plane/policy_engine.py +954 -0
  29. agent_control_plane/process_isolation.py +777 -0
  30. agent_control_plane/shadow_mode.py +310 -0
  31. agent_control_plane/signals.py +493 -0
  32. agent_control_plane/supervisor_agents.py +430 -0
  33. agent_control_plane/time_travel_debugger.py +557 -0
  34. agent_control_plane/tool_registry.py +452 -0
  35. agent_control_plane/vfs.py +697 -0
  36. agent_kernel/__init__.py +69 -0
  37. agent_kernel/analyzer.py +435 -0
  38. agent_kernel/auditor.py +36 -0
  39. agent_kernel/completeness_auditor.py +237 -0
  40. agent_kernel/detector.py +203 -0
  41. agent_kernel/kernel.py +744 -0
  42. agent_kernel/memory_manager.py +85 -0
  43. agent_kernel/models.py +374 -0
  44. agent_kernel/nudge_mechanism.py +263 -0
  45. agent_kernel/outcome_analyzer.py +338 -0
  46. agent_kernel/patcher.py +582 -0
  47. agent_kernel/semantic_analyzer.py +316 -0
  48. agent_kernel/semantic_purge.py +349 -0
  49. agent_kernel/simulator.py +449 -0
  50. agent_kernel/teacher.py +85 -0
  51. agent_kernel/triage.py +152 -0
  52. agent_os/__init__.py +409 -0
  53. agent_os/_adversarial_impl.py +200 -0
  54. agent_os/_circuit_breaker_impl.py +232 -0
  55. agent_os/_mcp_metrics.py +193 -0
  56. agent_os/adversarial.py +20 -0
  57. agent_os/agents_compat.py +490 -0
  58. agent_os/audit_logger.py +135 -0
  59. agent_os/base_agent.py +651 -0
  60. agent_os/circuit_breaker.py +34 -0
  61. agent_os/cli/__init__.py +659 -0
  62. agent_os/cli/cmd_audit.py +128 -0
  63. agent_os/cli/cmd_init.py +152 -0
  64. agent_os/cli/cmd_policy.py +41 -0
  65. agent_os/cli/cmd_policy_gen.py +180 -0
  66. agent_os/cli/cmd_validate.py +258 -0
  67. agent_os/cli/mcp_scan.py +265 -0
  68. agent_os/cli/output.py +192 -0
  69. agent_os/cli/policy_checker.py +330 -0
  70. agent_os/compat.py +74 -0
  71. agent_os/constraint_graph.py +234 -0
  72. agent_os/content_governance.py +140 -0
  73. agent_os/context_budget.py +305 -0
  74. agent_os/credential_redactor.py +224 -0
  75. agent_os/diff_policy.py +89 -0
  76. agent_os/egress_policy.py +159 -0
  77. agent_os/escalation.py +276 -0
  78. agent_os/event_bus.py +124 -0
  79. agent_os/exceptions.py +180 -0
  80. agent_os/execution_context_policy.py +141 -0
  81. agent_os/github_enterprise.py +96 -0
  82. agent_os/health.py +20 -0
  83. agent_os/integrations/__init__.py +279 -0
  84. agent_os/integrations/a2a_adapter.py +279 -0
  85. agent_os/integrations/agent_lightning/__init__.py +30 -0
  86. agent_os/integrations/anthropic_adapter.py +420 -0
  87. agent_os/integrations/autogen_adapter.py +620 -0
  88. agent_os/integrations/base.py +1137 -0
  89. agent_os/integrations/compat.py +229 -0
  90. agent_os/integrations/config.py +98 -0
  91. agent_os/integrations/conversation_guardian.py +957 -0
  92. agent_os/integrations/crewai_adapter.py +467 -0
  93. agent_os/integrations/drift_detector.py +425 -0
  94. agent_os/integrations/dry_run.py +124 -0
  95. agent_os/integrations/escalation.py +582 -0
  96. agent_os/integrations/gemini_adapter.py +364 -0
  97. agent_os/integrations/google_adk_adapter.py +633 -0
  98. agent_os/integrations/guardrails_adapter.py +394 -0
  99. agent_os/integrations/health.py +197 -0
  100. agent_os/integrations/langchain_adapter.py +654 -0
  101. agent_os/integrations/llamafirewall.py +343 -0
  102. agent_os/integrations/llamaindex_adapter.py +188 -0
  103. agent_os/integrations/logging.py +191 -0
  104. agent_os/integrations/maf_adapter.py +631 -0
  105. agent_os/integrations/mistral_adapter.py +365 -0
  106. agent_os/integrations/openai_adapter.py +816 -0
  107. agent_os/integrations/openai_agents_sdk.py +406 -0
  108. agent_os/integrations/policy_compose.py +171 -0
  109. agent_os/integrations/profiling.py +144 -0
  110. agent_os/integrations/pydantic_ai_adapter.py +420 -0
  111. agent_os/integrations/rate_limiter.py +130 -0
  112. agent_os/integrations/rbac.py +143 -0
  113. agent_os/integrations/registry.py +113 -0
  114. agent_os/integrations/scope_guard.py +303 -0
  115. agent_os/integrations/semantic_kernel_adapter.py +769 -0
  116. agent_os/integrations/smolagents_adapter.py +629 -0
  117. agent_os/integrations/templates.py +178 -0
  118. agent_os/integrations/token_budget.py +134 -0
  119. agent_os/integrations/tool_aliases.py +190 -0
  120. agent_os/integrations/webhooks.py +177 -0
  121. agent_os/lite.py +208 -0
  122. agent_os/mcp_gateway.py +385 -0
  123. agent_os/mcp_message_signer.py +273 -0
  124. agent_os/mcp_protocols.py +161 -0
  125. agent_os/mcp_response_scanner.py +232 -0
  126. agent_os/mcp_security.py +924 -0
  127. agent_os/mcp_session_auth.py +231 -0
  128. agent_os/mcp_sliding_rate_limiter.py +184 -0
  129. agent_os/memory_guard.py +409 -0
  130. agent_os/metrics.py +134 -0
  131. agent_os/mute.py +428 -0
  132. agent_os/mute_agent.py +209 -0
  133. agent_os/policies/__init__.py +77 -0
  134. agent_os/policies/async_evaluator.py +275 -0
  135. agent_os/policies/backends.py +670 -0
  136. agent_os/policies/bridge.py +169 -0
  137. agent_os/policies/budget.py +85 -0
  138. agent_os/policies/cli.py +294 -0
  139. agent_os/policies/conflict_resolution.py +270 -0
  140. agent_os/policies/data_classification.py +252 -0
  141. agent_os/policies/evaluator.py +239 -0
  142. agent_os/policies/policy_schema.json +228 -0
  143. agent_os/policies/rate_limiting.py +145 -0
  144. agent_os/policies/schema.py +115 -0
  145. agent_os/policies/shared.py +331 -0
  146. agent_os/prompt_injection.py +694 -0
  147. agent_os/providers.py +182 -0
  148. agent_os/py.typed +0 -0
  149. agent_os/retry.py +81 -0
  150. agent_os/reversibility.py +251 -0
  151. agent_os/sandbox.py +432 -0
  152. agent_os/sandbox_provider.py +140 -0
  153. agent_os/secure_codegen.py +525 -0
  154. agent_os/security_skills.py +538 -0
  155. agent_os/semantic_policy.py +422 -0
  156. agent_os/server/__init__.py +15 -0
  157. agent_os/server/__main__.py +25 -0
  158. agent_os/server/app.py +277 -0
  159. agent_os/server/models.py +104 -0
  160. agent_os/shift_left_metrics.py +130 -0
  161. agent_os/stateless.py +742 -0
  162. agent_os/supervisor.py +148 -0
  163. agent_os/task_outcome.py +148 -0
  164. agent_os/transparency.py +181 -0
  165. agent_os/trust_root.py +128 -0
  166. agent_os_kernel-3.1.0.dist-info/METADATA +1269 -0
  167. agent_os_kernel-3.1.0.dist-info/RECORD +337 -0
  168. agent_os_kernel-3.1.0.dist-info/WHEEL +4 -0
  169. agent_os_kernel-3.1.0.dist-info/entry_points.txt +2 -0
  170. agent_os_kernel-3.1.0.dist-info/licenses/LICENSE +21 -0
  171. agent_os_observability/__init__.py +27 -0
  172. agent_os_observability/dashboards.py +898 -0
  173. agent_os_observability/metrics.py +398 -0
  174. agent_os_observability/server.py +223 -0
  175. agent_os_observability/tracer.py +232 -0
  176. agent_primitives/__init__.py +24 -0
  177. agent_primitives/failures.py +84 -0
  178. agent_primitives/py.typed +0 -0
  179. amb_core/__init__.py +177 -0
  180. amb_core/adapters/__init__.py +57 -0
  181. amb_core/adapters/aws_sqs_broker.py +376 -0
  182. amb_core/adapters/azure_servicebus_broker.py +340 -0
  183. amb_core/adapters/kafka_broker.py +260 -0
  184. amb_core/adapters/nats_broker.py +285 -0
  185. amb_core/adapters/rabbitmq_broker.py +235 -0
  186. amb_core/adapters/redis_broker.py +262 -0
  187. amb_core/broker.py +145 -0
  188. amb_core/bus.py +481 -0
  189. amb_core/cloudevents.py +509 -0
  190. amb_core/dlq.py +345 -0
  191. amb_core/hf_utils.py +536 -0
  192. amb_core/memory_broker.py +410 -0
  193. amb_core/models.py +141 -0
  194. amb_core/persistence.py +529 -0
  195. amb_core/schema.py +294 -0
  196. amb_core/tracing.py +358 -0
  197. atr/__init__.py +640 -0
  198. atr/access.py +348 -0
  199. atr/composition.py +645 -0
  200. atr/decorator.py +357 -0
  201. atr/executor.py +384 -0
  202. atr/health.py +557 -0
  203. atr/hf_utils.py +449 -0
  204. atr/injection.py +422 -0
  205. atr/metrics.py +440 -0
  206. atr/policies.py +403 -0
  207. atr/py.typed +2 -0
  208. atr/registry.py +452 -0
  209. atr/schema.py +480 -0
  210. atr/tools/safe/__init__.py +75 -0
  211. atr/tools/safe/calculator.py +467 -0
  212. atr/tools/safe/datetime_tool.py +443 -0
  213. atr/tools/safe/file_reader.py +402 -0
  214. atr/tools/safe/http_client.py +316 -0
  215. atr/tools/safe/json_parser.py +374 -0
  216. atr/tools/safe/text_tool.py +537 -0
  217. atr/tools/safe/toolkit.py +175 -0
  218. caas/__init__.py +162 -0
  219. caas/api/__init__.py +7 -0
  220. caas/api/server.py +1328 -0
  221. caas/caching.py +834 -0
  222. caas/cli.py +210 -0
  223. caas/conversation.py +223 -0
  224. caas/decay.py +72 -0
  225. caas/detection/__init__.py +9 -0
  226. caas/detection/detector.py +238 -0
  227. caas/enrichment.py +130 -0
  228. caas/gateway/__init__.py +27 -0
  229. caas/gateway/trust_gateway.py +474 -0
  230. caas/hf_utils.py +479 -0
  231. caas/ingestion/__init__.py +23 -0
  232. caas/ingestion/processors.py +253 -0
  233. caas/ingestion/structure_parser.py +188 -0
  234. caas/models.py +356 -0
  235. caas/pragmatic_truth.py +444 -0
  236. caas/routing/__init__.py +10 -0
  237. caas/routing/heuristic_router.py +58 -0
  238. caas/storage/__init__.py +9 -0
  239. caas/storage/store.py +389 -0
  240. caas/triad.py +213 -0
  241. caas/tuning/__init__.py +9 -0
  242. caas/tuning/tuner.py +329 -0
  243. caas/vfs/__init__.py +14 -0
  244. caas/vfs/filesystem.py +452 -0
  245. cmvk/__init__.py +218 -0
  246. cmvk/audit.py +402 -0
  247. cmvk/benchmarks.py +478 -0
  248. cmvk/constitutional.py +904 -0
  249. cmvk/hf_utils.py +301 -0
  250. cmvk/metrics.py +473 -0
  251. cmvk/profiles.py +300 -0
  252. cmvk/py.typed +0 -0
  253. cmvk/types.py +12 -0
  254. cmvk/verification.py +956 -0
  255. emk/__init__.py +89 -0
  256. emk/causal.py +352 -0
  257. emk/hf_utils.py +421 -0
  258. emk/indexer.py +83 -0
  259. emk/py.typed +0 -0
  260. emk/schema.py +204 -0
  261. emk/sleep_cycle.py +347 -0
  262. emk/store.py +281 -0
  263. iatp/__init__.py +166 -0
  264. iatp/attestation.py +461 -0
  265. iatp/cli.py +317 -0
  266. iatp/hf_utils.py +472 -0
  267. iatp/ipc_pipes.py +580 -0
  268. iatp/main.py +412 -0
  269. iatp/models/__init__.py +447 -0
  270. iatp/policy_engine.py +337 -0
  271. iatp/py.typed +2 -0
  272. iatp/recovery.py +321 -0
  273. iatp/security/__init__.py +270 -0
  274. iatp/sidecar/__init__.py +519 -0
  275. iatp/telemetry/__init__.py +164 -0
  276. iatp/tests/__init__.py +1 -0
  277. iatp/tests/test_attestation.py +370 -0
  278. iatp/tests/test_cli.py +131 -0
  279. iatp/tests/test_ed25519_attestation.py +211 -0
  280. iatp/tests/test_models.py +130 -0
  281. iatp/tests/test_policy_engine.py +347 -0
  282. iatp/tests/test_recovery.py +281 -0
  283. iatp/tests/test_security.py +222 -0
  284. iatp/tests/test_sidecar.py +167 -0
  285. iatp/tests/test_telemetry.py +175 -0
  286. mcp_kernel_server/__init__.py +28 -0
  287. mcp_kernel_server/cli.py +274 -0
  288. mcp_kernel_server/resources.py +217 -0
  289. mcp_kernel_server/server.py +564 -0
  290. mcp_kernel_server/tools.py +1174 -0
  291. mute_agent/__init__.py +68 -0
  292. mute_agent/core/__init__.py +1 -0
  293. mute_agent/core/execution_agent.py +166 -0
  294. mute_agent/core/handshake_protocol.py +201 -0
  295. mute_agent/core/reasoning_agent.py +238 -0
  296. mute_agent/knowledge_graph/__init__.py +1 -0
  297. mute_agent/knowledge_graph/graph_elements.py +65 -0
  298. mute_agent/knowledge_graph/multidimensional_graph.py +170 -0
  299. mute_agent/knowledge_graph/subgraph.py +224 -0
  300. mute_agent/listener/__init__.py +43 -0
  301. mute_agent/listener/adapters/__init__.py +31 -0
  302. mute_agent/listener/adapters/base_adapter.py +189 -0
  303. mute_agent/listener/adapters/caas_adapter.py +344 -0
  304. mute_agent/listener/adapters/control_plane_adapter.py +436 -0
  305. mute_agent/listener/adapters/iatp_adapter.py +332 -0
  306. mute_agent/listener/adapters/scak_adapter.py +251 -0
  307. mute_agent/listener/listener.py +610 -0
  308. mute_agent/listener/state_observer.py +436 -0
  309. mute_agent/listener/threshold_config.py +313 -0
  310. mute_agent/super_system/__init__.py +1 -0
  311. mute_agent/super_system/router.py +204 -0
  312. mute_agent/visualization/__init__.py +10 -0
  313. mute_agent/visualization/graph_debugger.py +502 -0
  314. nexus/README.md +60 -0
  315. nexus/__init__.py +51 -0
  316. nexus/arbiter.py +359 -0
  317. nexus/client.py +466 -0
  318. nexus/dmz.py +444 -0
  319. nexus/escrow.py +430 -0
  320. nexus/exceptions.py +286 -0
  321. nexus/pyproject.toml +36 -0
  322. nexus/registry.py +393 -0
  323. nexus/reputation.py +425 -0
  324. nexus/schemas/__init__.py +51 -0
  325. nexus/schemas/compliance.py +276 -0
  326. nexus/schemas/escrow.py +251 -0
  327. nexus/schemas/manifest.py +225 -0
  328. nexus/schemas/receipt.py +208 -0
  329. nexus/tests/__init__.py +0 -0
  330. nexus/tests/conftest.py +146 -0
  331. nexus/tests/test_arbiter.py +192 -0
  332. nexus/tests/test_dmz.py +194 -0
  333. nexus/tests/test_escrow.py +276 -0
  334. nexus/tests/test_exceptions.py +225 -0
  335. nexus/tests/test_registry.py +232 -0
  336. nexus/tests/test_reputation.py +328 -0
  337. 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
+ )