ouroboros-ai 0.2.3__py3-none-any.whl → 0.4.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.

Potentially problematic release.


This version of ouroboros-ai might be problematic. Click here for more details.

Files changed (44) hide show
  1. ouroboros/__init__.py +1 -1
  2. ouroboros/bigbang/__init__.py +9 -0
  3. ouroboros/bigbang/interview.py +16 -18
  4. ouroboros/bigbang/ontology.py +180 -0
  5. ouroboros/cli/commands/__init__.py +2 -0
  6. ouroboros/cli/commands/init.py +162 -97
  7. ouroboros/cli/commands/mcp.py +161 -0
  8. ouroboros/cli/commands/run.py +165 -27
  9. ouroboros/cli/main.py +2 -1
  10. ouroboros/core/ontology_aspect.py +455 -0
  11. ouroboros/core/ontology_questions.py +462 -0
  12. ouroboros/evaluation/__init__.py +16 -1
  13. ouroboros/evaluation/consensus.py +569 -11
  14. ouroboros/evaluation/models.py +81 -0
  15. ouroboros/events/ontology.py +135 -0
  16. ouroboros/mcp/__init__.py +83 -0
  17. ouroboros/mcp/client/__init__.py +20 -0
  18. ouroboros/mcp/client/adapter.py +632 -0
  19. ouroboros/mcp/client/manager.py +600 -0
  20. ouroboros/mcp/client/protocol.py +161 -0
  21. ouroboros/mcp/errors.py +377 -0
  22. ouroboros/mcp/resources/__init__.py +22 -0
  23. ouroboros/mcp/resources/handlers.py +328 -0
  24. ouroboros/mcp/server/__init__.py +21 -0
  25. ouroboros/mcp/server/adapter.py +408 -0
  26. ouroboros/mcp/server/protocol.py +291 -0
  27. ouroboros/mcp/server/security.py +636 -0
  28. ouroboros/mcp/tools/__init__.py +24 -0
  29. ouroboros/mcp/tools/definitions.py +351 -0
  30. ouroboros/mcp/tools/registry.py +269 -0
  31. ouroboros/mcp/types.py +333 -0
  32. ouroboros/orchestrator/__init__.py +31 -0
  33. ouroboros/orchestrator/events.py +40 -0
  34. ouroboros/orchestrator/mcp_config.py +419 -0
  35. ouroboros/orchestrator/mcp_tools.py +483 -0
  36. ouroboros/orchestrator/runner.py +119 -2
  37. ouroboros/providers/claude_code_adapter.py +75 -0
  38. ouroboros/strategies/__init__.py +23 -0
  39. ouroboros/strategies/devil_advocate.py +197 -0
  40. {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/METADATA +73 -17
  41. {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/RECORD +44 -19
  42. {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/WHEEL +0 -0
  43. {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/entry_points.txt +0 -0
  44. {ouroboros_ai-0.2.3.dist-info → ouroboros_ai-0.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,161 @@
1
+ """MCP Client protocol definition.
2
+
3
+ This module defines the MCPClient protocol that all MCP client implementations
4
+ must follow. It provides a unified interface for connecting to MCP servers
5
+ and using their tools, resources, and prompts.
6
+ """
7
+
8
+ from collections.abc import Sequence
9
+ from typing import Any, Protocol
10
+
11
+ from ouroboros.core.types import Result
12
+ from ouroboros.mcp.errors import MCPClientError
13
+ from ouroboros.mcp.types import (
14
+ MCPPromptDefinition,
15
+ MCPResourceContent,
16
+ MCPResourceDefinition,
17
+ MCPServerConfig,
18
+ MCPServerInfo,
19
+ MCPToolDefinition,
20
+ MCPToolResult,
21
+ )
22
+
23
+
24
+ class MCPClient(Protocol):
25
+ """Protocol for MCP client implementations.
26
+
27
+ This protocol defines the interface that all MCP client adapters must
28
+ implement. It supports connecting to MCP servers and using their
29
+ tools, resources, and prompts.
30
+
31
+ All methods return Result[T, MCPClientError] to handle expected failures
32
+ without exceptions. Exceptions are reserved for programming errors.
33
+
34
+ Example:
35
+ async with MCPClientAdapter() as client:
36
+ result = await client.connect(config)
37
+ if result.is_err:
38
+ log.error("Failed to connect", error=result.error)
39
+ return
40
+
41
+ tools_result = await client.list_tools()
42
+ if tools_result.is_ok:
43
+ for tool in tools_result.value:
44
+ print(f"Tool: {tool.name}")
45
+
46
+ call_result = await client.call_tool(
47
+ "my_tool",
48
+ {"arg1": "value1"}
49
+ )
50
+ if call_result.is_ok:
51
+ print(call_result.value.text_content)
52
+ """
53
+
54
+ async def connect(
55
+ self,
56
+ config: MCPServerConfig,
57
+ ) -> Result[MCPServerInfo, MCPClientError]:
58
+ """Connect to an MCP server.
59
+
60
+ Establishes a connection to the MCP server specified by the config.
61
+ This method handles retries internally and returns server information
62
+ on success.
63
+
64
+ Args:
65
+ config: Configuration for the server connection.
66
+
67
+ Returns:
68
+ Result containing server info on success or MCPClientError on failure.
69
+ """
70
+ ...
71
+
72
+ async def disconnect(self) -> Result[None, MCPClientError]:
73
+ """Disconnect from the current MCP server.
74
+
75
+ Cleanly closes the connection to the server. Safe to call even if
76
+ not connected.
77
+
78
+ Returns:
79
+ Result containing None on success or MCPClientError on failure.
80
+ """
81
+ ...
82
+
83
+ @property
84
+ def is_connected(self) -> bool:
85
+ """Return True if currently connected to a server."""
86
+ ...
87
+
88
+ @property
89
+ def server_info(self) -> MCPServerInfo | None:
90
+ """Return information about the connected server, or None if not connected."""
91
+ ...
92
+
93
+ async def list_tools(self) -> Result[Sequence[MCPToolDefinition], MCPClientError]:
94
+ """List available tools from the connected server.
95
+
96
+ Returns:
97
+ Result containing sequence of tool definitions or MCPClientError.
98
+ """
99
+ ...
100
+
101
+ async def call_tool(
102
+ self,
103
+ name: str,
104
+ arguments: dict[str, Any] | None = None,
105
+ ) -> Result[MCPToolResult, MCPClientError]:
106
+ """Call a tool on the connected server.
107
+
108
+ Args:
109
+ name: Name of the tool to call.
110
+ arguments: Arguments to pass to the tool.
111
+
112
+ Returns:
113
+ Result containing tool result or MCPClientError.
114
+ """
115
+ ...
116
+
117
+ async def list_resources(self) -> Result[Sequence[MCPResourceDefinition], MCPClientError]:
118
+ """List available resources from the connected server.
119
+
120
+ Returns:
121
+ Result containing sequence of resource definitions or MCPClientError.
122
+ """
123
+ ...
124
+
125
+ async def read_resource(
126
+ self,
127
+ uri: str,
128
+ ) -> Result[MCPResourceContent, MCPClientError]:
129
+ """Read a resource from the connected server.
130
+
131
+ Args:
132
+ uri: URI of the resource to read.
133
+
134
+ Returns:
135
+ Result containing resource content or MCPClientError.
136
+ """
137
+ ...
138
+
139
+ async def list_prompts(self) -> Result[Sequence[MCPPromptDefinition], MCPClientError]:
140
+ """List available prompts from the connected server.
141
+
142
+ Returns:
143
+ Result containing sequence of prompt definitions or MCPClientError.
144
+ """
145
+ ...
146
+
147
+ async def get_prompt(
148
+ self,
149
+ name: str,
150
+ arguments: dict[str, str] | None = None,
151
+ ) -> Result[str, MCPClientError]:
152
+ """Get a prompt from the connected server.
153
+
154
+ Args:
155
+ name: Name of the prompt to get.
156
+ arguments: Arguments to fill in the prompt template.
157
+
158
+ Returns:
159
+ Result containing the prompt text or MCPClientError.
160
+ """
161
+ ...
@@ -0,0 +1,377 @@
1
+ """MCP error hierarchy for Ouroboros.
2
+
3
+ This module defines MCP-specific exceptions extending the base Ouroboros
4
+ error hierarchy. These are used for both unexpected errors (bugs) and
5
+ as error types in Result for expected MCP failures.
6
+
7
+ Exception Hierarchy:
8
+ OuroborosError (base from core.errors)
9
+ └── MCPError (MCP base)
10
+ ├── MCPClientError - Client-side failures (connection, protocol)
11
+ │ ├── MCPConnectionError - Failed to connect to server
12
+ │ ├── MCPTimeoutError - Request timeout
13
+ │ └── MCPProtocolError - Protocol-level errors
14
+ └── MCPServerError - Server-side failures
15
+ ├── MCPAuthError - Authentication/authorization failures
16
+ ├── MCPResourceNotFoundError - Resource not found
17
+ └── MCPToolError - Tool execution failures
18
+ """
19
+
20
+ from typing import Any
21
+
22
+ from ouroboros.core.errors import OuroborosError
23
+
24
+
25
+ class MCPError(OuroborosError):
26
+ """Base exception for all MCP-related errors.
27
+
28
+ All MCP-specific exceptions inherit from this class and OuroborosError.
29
+ This allows catching all MCP errors with a single except clause.
30
+
31
+ Attributes:
32
+ message: Human-readable error description.
33
+ server_name: Name of the MCP server involved (if applicable).
34
+ is_retriable: Whether the operation can be retried.
35
+ """
36
+
37
+ def __init__(
38
+ self,
39
+ message: str,
40
+ *,
41
+ server_name: str | None = None,
42
+ is_retriable: bool = False,
43
+ details: dict[str, Any] | None = None,
44
+ ) -> None:
45
+ """Initialize the MCP error.
46
+
47
+ Args:
48
+ message: Human-readable error description.
49
+ server_name: Name of the MCP server involved.
50
+ is_retriable: Whether the operation can be retried.
51
+ details: Optional dict with additional context.
52
+ """
53
+ super().__init__(message, details)
54
+ self.server_name = server_name
55
+ self.is_retriable = is_retriable
56
+
57
+ def __str__(self) -> str:
58
+ """Return string representation of the error."""
59
+ parts = [self.message]
60
+ if self.server_name:
61
+ parts.append(f"server={self.server_name}")
62
+ if self.is_retriable:
63
+ parts.append("retriable=True")
64
+ if self.details:
65
+ parts.append(f"details={self.details}")
66
+ return " ".join(parts)
67
+
68
+
69
+ class MCPClientError(MCPError):
70
+ """Error from MCP client operations.
71
+
72
+ Raised when client-side MCP operations fail (connection, protocol errors).
73
+ This is the base class for more specific client errors.
74
+
75
+ Attributes:
76
+ request_id: ID of the request that failed (if applicable).
77
+ """
78
+
79
+ def __init__(
80
+ self,
81
+ message: str,
82
+ *,
83
+ server_name: str | None = None,
84
+ request_id: str | None = None,
85
+ is_retriable: bool = False,
86
+ details: dict[str, Any] | None = None,
87
+ ) -> None:
88
+ """Initialize client error.
89
+
90
+ Args:
91
+ message: Human-readable error description.
92
+ server_name: Name of the MCP server.
93
+ request_id: ID of the request that failed.
94
+ is_retriable: Whether the operation can be retried.
95
+ details: Optional dict with additional context.
96
+ """
97
+ super().__init__(
98
+ message,
99
+ server_name=server_name,
100
+ is_retriable=is_retriable,
101
+ details=details,
102
+ )
103
+ self.request_id = request_id
104
+
105
+ @classmethod
106
+ def from_exception(
107
+ cls,
108
+ exc: Exception,
109
+ *,
110
+ server_name: str | None = None,
111
+ request_id: str | None = None,
112
+ is_retriable: bool = False,
113
+ ) -> MCPClientError:
114
+ """Create MCPClientError from another exception.
115
+
116
+ Args:
117
+ exc: The original exception.
118
+ server_name: Name of the MCP server.
119
+ request_id: ID of the request that failed.
120
+ is_retriable: Whether the operation can be retried.
121
+
122
+ Returns:
123
+ An MCPClientError wrapping the original exception.
124
+ """
125
+ error = cls(
126
+ str(exc),
127
+ server_name=server_name,
128
+ request_id=request_id,
129
+ is_retriable=is_retriable,
130
+ details={"original_exception": type(exc).__name__},
131
+ )
132
+ error.__cause__ = exc
133
+ return error
134
+
135
+
136
+ class MCPConnectionError(MCPClientError):
137
+ """Failed to connect to an MCP server.
138
+
139
+ Raised when the client cannot establish a connection to the server.
140
+ This is typically retriable after a delay.
141
+ """
142
+
143
+ def __init__(
144
+ self,
145
+ message: str,
146
+ *,
147
+ server_name: str | None = None,
148
+ transport: str | None = None,
149
+ details: dict[str, Any] | None = None,
150
+ ) -> None:
151
+ """Initialize connection error.
152
+
153
+ Args:
154
+ message: Human-readable error description.
155
+ server_name: Name of the MCP server.
156
+ transport: Transport type (stdio, sse, etc.).
157
+ details: Optional dict with additional context.
158
+ """
159
+ super().__init__(
160
+ message,
161
+ server_name=server_name,
162
+ is_retriable=True,
163
+ details=details,
164
+ )
165
+ self.transport = transport
166
+
167
+
168
+ class MCPTimeoutError(MCPClientError):
169
+ """MCP request timed out.
170
+
171
+ Raised when an MCP request exceeds the configured timeout.
172
+ This is typically retriable with exponential backoff.
173
+ """
174
+
175
+ def __init__(
176
+ self,
177
+ message: str,
178
+ *,
179
+ server_name: str | None = None,
180
+ timeout_seconds: float | None = None,
181
+ operation: str | None = None,
182
+ details: dict[str, Any] | None = None,
183
+ ) -> None:
184
+ """Initialize timeout error.
185
+
186
+ Args:
187
+ message: Human-readable error description.
188
+ server_name: Name of the MCP server.
189
+ timeout_seconds: The timeout value that was exceeded.
190
+ operation: The operation that timed out.
191
+ details: Optional dict with additional context.
192
+ """
193
+ super().__init__(
194
+ message,
195
+ server_name=server_name,
196
+ is_retriable=True,
197
+ details=details,
198
+ )
199
+ self.timeout_seconds = timeout_seconds
200
+ self.operation = operation
201
+
202
+
203
+ class MCPProtocolError(MCPClientError):
204
+ """MCP protocol-level error.
205
+
206
+ Raised when there's a protocol violation or unexpected response format.
207
+ This is generally not retriable as it indicates a compatibility issue.
208
+ """
209
+
210
+ def __init__(
211
+ self,
212
+ message: str,
213
+ *,
214
+ server_name: str | None = None,
215
+ error_code: int | None = None,
216
+ details: dict[str, Any] | None = None,
217
+ ) -> None:
218
+ """Initialize protocol error.
219
+
220
+ Args:
221
+ message: Human-readable error description.
222
+ server_name: Name of the MCP server.
223
+ error_code: Protocol error code if available.
224
+ details: Optional dict with additional context.
225
+ """
226
+ super().__init__(
227
+ message,
228
+ server_name=server_name,
229
+ is_retriable=False,
230
+ details=details,
231
+ )
232
+ self.error_code = error_code
233
+
234
+
235
+ class MCPServerError(MCPError):
236
+ """Error from MCP server operations.
237
+
238
+ Raised when server-side MCP operations fail. This is the base class
239
+ for more specific server errors.
240
+ """
241
+
242
+ def __init__(
243
+ self,
244
+ message: str,
245
+ *,
246
+ server_name: str | None = None,
247
+ is_retriable: bool = False,
248
+ details: dict[str, Any] | None = None,
249
+ ) -> None:
250
+ """Initialize server error.
251
+
252
+ Args:
253
+ message: Human-readable error description.
254
+ server_name: Name of the MCP server.
255
+ is_retriable: Whether the operation can be retried.
256
+ details: Optional dict with additional context.
257
+ """
258
+ super().__init__(
259
+ message,
260
+ server_name=server_name,
261
+ is_retriable=is_retriable,
262
+ details=details,
263
+ )
264
+
265
+
266
+ class MCPAuthError(MCPServerError):
267
+ """Authentication or authorization failure.
268
+
269
+ Raised when authentication fails or the client lacks permission
270
+ for the requested operation.
271
+
272
+ Attributes:
273
+ auth_method: The authentication method that failed.
274
+ required_permission: The permission that was required.
275
+ """
276
+
277
+ def __init__(
278
+ self,
279
+ message: str,
280
+ *,
281
+ server_name: str | None = None,
282
+ auth_method: str | None = None,
283
+ required_permission: str | None = None,
284
+ details: dict[str, Any] | None = None,
285
+ ) -> None:
286
+ """Initialize auth error.
287
+
288
+ Args:
289
+ message: Human-readable error description.
290
+ server_name: Name of the MCP server.
291
+ auth_method: The authentication method that failed.
292
+ required_permission: The permission that was required.
293
+ details: Optional dict with additional context.
294
+ """
295
+ super().__init__(
296
+ message,
297
+ server_name=server_name,
298
+ is_retriable=False,
299
+ details=details,
300
+ )
301
+ self.auth_method = auth_method
302
+ self.required_permission = required_permission
303
+
304
+
305
+ class MCPResourceNotFoundError(MCPServerError):
306
+ """Requested resource not found.
307
+
308
+ Raised when a requested resource (tool, prompt, resource URI) does not exist.
309
+ """
310
+
311
+ def __init__(
312
+ self,
313
+ message: str,
314
+ *,
315
+ server_name: str | None = None,
316
+ resource_type: str | None = None,
317
+ resource_id: str | None = None,
318
+ details: dict[str, Any] | None = None,
319
+ ) -> None:
320
+ """Initialize resource not found error.
321
+
322
+ Args:
323
+ message: Human-readable error description.
324
+ server_name: Name of the MCP server.
325
+ resource_type: Type of resource (tool, prompt, resource).
326
+ resource_id: ID or name of the resource.
327
+ details: Optional dict with additional context.
328
+ """
329
+ super().__init__(
330
+ message,
331
+ server_name=server_name,
332
+ is_retriable=False,
333
+ details=details,
334
+ )
335
+ self.resource_type = resource_type
336
+ self.resource_id = resource_id
337
+
338
+
339
+ class MCPToolError(MCPServerError):
340
+ """Error during tool execution.
341
+
342
+ Raised when a tool invocation fails during execution.
343
+ Extends MCPServerError since tools are server-side operations.
344
+
345
+ Attributes:
346
+ tool_name: Name of the tool that failed.
347
+ error_code: Tool-specific error code if available.
348
+ """
349
+
350
+ def __init__(
351
+ self,
352
+ message: str,
353
+ *,
354
+ server_name: str | None = None,
355
+ tool_name: str | None = None,
356
+ error_code: str | None = None,
357
+ is_retriable: bool = False,
358
+ details: dict[str, Any] | None = None,
359
+ ) -> None:
360
+ """Initialize tool error.
361
+
362
+ Args:
363
+ message: Human-readable error description.
364
+ server_name: Name of the MCP server.
365
+ tool_name: Name of the tool that failed.
366
+ error_code: Tool-specific error code.
367
+ is_retriable: Whether the operation can be retried.
368
+ details: Optional dict with additional context.
369
+ """
370
+ super().__init__(
371
+ message,
372
+ server_name=server_name,
373
+ is_retriable=is_retriable,
374
+ details=details,
375
+ )
376
+ self.tool_name = tool_name
377
+ self.error_code = error_code
@@ -0,0 +1,22 @@
1
+ """MCP Resources package.
2
+
3
+ This package provides resource handlers for the MCP server.
4
+
5
+ Public API:
6
+ OUROBOROS_RESOURCES: List of available resource definitions
7
+ Resource handlers for seeds, sessions, and events
8
+ """
9
+
10
+ from ouroboros.mcp.resources.handlers import (
11
+ OUROBOROS_RESOURCES,
12
+ events_handler,
13
+ seeds_handler,
14
+ sessions_handler,
15
+ )
16
+
17
+ __all__ = [
18
+ "OUROBOROS_RESOURCES",
19
+ "seeds_handler",
20
+ "sessions_handler",
21
+ "events_handler",
22
+ ]