nc1709 1.15.4__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 (86) hide show
  1. nc1709/__init__.py +13 -0
  2. nc1709/agent/__init__.py +36 -0
  3. nc1709/agent/core.py +505 -0
  4. nc1709/agent/mcp_bridge.py +245 -0
  5. nc1709/agent/permissions.py +298 -0
  6. nc1709/agent/tools/__init__.py +21 -0
  7. nc1709/agent/tools/base.py +440 -0
  8. nc1709/agent/tools/bash_tool.py +367 -0
  9. nc1709/agent/tools/file_tools.py +454 -0
  10. nc1709/agent/tools/notebook_tools.py +516 -0
  11. nc1709/agent/tools/search_tools.py +322 -0
  12. nc1709/agent/tools/task_tool.py +284 -0
  13. nc1709/agent/tools/web_tools.py +555 -0
  14. nc1709/agents/__init__.py +17 -0
  15. nc1709/agents/auto_fix.py +506 -0
  16. nc1709/agents/test_generator.py +507 -0
  17. nc1709/checkpoints.py +372 -0
  18. nc1709/cli.py +3380 -0
  19. nc1709/cli_ui.py +1080 -0
  20. nc1709/cognitive/__init__.py +149 -0
  21. nc1709/cognitive/anticipation.py +594 -0
  22. nc1709/cognitive/context_engine.py +1046 -0
  23. nc1709/cognitive/council.py +824 -0
  24. nc1709/cognitive/learning.py +761 -0
  25. nc1709/cognitive/router.py +583 -0
  26. nc1709/cognitive/system.py +519 -0
  27. nc1709/config.py +155 -0
  28. nc1709/custom_commands.py +300 -0
  29. nc1709/executor.py +333 -0
  30. nc1709/file_controller.py +354 -0
  31. nc1709/git_integration.py +308 -0
  32. nc1709/github_integration.py +477 -0
  33. nc1709/image_input.py +446 -0
  34. nc1709/linting.py +519 -0
  35. nc1709/llm_adapter.py +667 -0
  36. nc1709/logger.py +192 -0
  37. nc1709/mcp/__init__.py +18 -0
  38. nc1709/mcp/client.py +370 -0
  39. nc1709/mcp/manager.py +407 -0
  40. nc1709/mcp/protocol.py +210 -0
  41. nc1709/mcp/server.py +473 -0
  42. nc1709/memory/__init__.py +20 -0
  43. nc1709/memory/embeddings.py +325 -0
  44. nc1709/memory/indexer.py +474 -0
  45. nc1709/memory/sessions.py +432 -0
  46. nc1709/memory/vector_store.py +451 -0
  47. nc1709/models/__init__.py +86 -0
  48. nc1709/models/detector.py +377 -0
  49. nc1709/models/formats.py +315 -0
  50. nc1709/models/manager.py +438 -0
  51. nc1709/models/registry.py +497 -0
  52. nc1709/performance/__init__.py +343 -0
  53. nc1709/performance/cache.py +705 -0
  54. nc1709/performance/pipeline.py +611 -0
  55. nc1709/performance/tiering.py +543 -0
  56. nc1709/plan_mode.py +362 -0
  57. nc1709/plugins/__init__.py +17 -0
  58. nc1709/plugins/agents/__init__.py +18 -0
  59. nc1709/plugins/agents/django_agent.py +912 -0
  60. nc1709/plugins/agents/docker_agent.py +623 -0
  61. nc1709/plugins/agents/fastapi_agent.py +887 -0
  62. nc1709/plugins/agents/git_agent.py +731 -0
  63. nc1709/plugins/agents/nextjs_agent.py +867 -0
  64. nc1709/plugins/base.py +359 -0
  65. nc1709/plugins/manager.py +411 -0
  66. nc1709/plugins/registry.py +337 -0
  67. nc1709/progress.py +443 -0
  68. nc1709/prompts/__init__.py +22 -0
  69. nc1709/prompts/agent_system.py +180 -0
  70. nc1709/prompts/task_prompts.py +340 -0
  71. nc1709/prompts/unified_prompt.py +133 -0
  72. nc1709/reasoning_engine.py +541 -0
  73. nc1709/remote_client.py +266 -0
  74. nc1709/shell_completions.py +349 -0
  75. nc1709/slash_commands.py +649 -0
  76. nc1709/task_classifier.py +408 -0
  77. nc1709/version_check.py +177 -0
  78. nc1709/web/__init__.py +8 -0
  79. nc1709/web/server.py +950 -0
  80. nc1709/web/templates/index.html +1127 -0
  81. nc1709-1.15.4.dist-info/METADATA +858 -0
  82. nc1709-1.15.4.dist-info/RECORD +86 -0
  83. nc1709-1.15.4.dist-info/WHEEL +5 -0
  84. nc1709-1.15.4.dist-info/entry_points.txt +2 -0
  85. nc1709-1.15.4.dist-info/licenses/LICENSE +9 -0
  86. nc1709-1.15.4.dist-info/top_level.txt +1 -0
nc1709/mcp/manager.py ADDED
@@ -0,0 +1,407 @@
1
+ """
2
+ MCP Manager
3
+ High-level manager for MCP server and client operations
4
+ """
5
+ import asyncio
6
+ from typing import Dict, Any, Optional, List, Callable
7
+ from pathlib import Path
8
+
9
+ from .server import MCPServer, ToolResult
10
+ from .client import MCPClient
11
+ from .protocol import MCPTool, MCPResource, MCPToolParameter
12
+
13
+
14
+ class MCPManager:
15
+ """
16
+ High-level manager for MCP functionality.
17
+
18
+ Provides a unified interface for:
19
+ - Running NC1709 as an MCP server
20
+ - Connecting to external MCP servers as a client
21
+ - Managing tools and resources across connections
22
+ """
23
+
24
+ def __init__(self, name: str = "nc1709", version: str = "1.0.0"):
25
+ """Initialize the MCP manager
26
+
27
+ Args:
28
+ name: Name for the local MCP server
29
+ version: Version for the local MCP server
30
+ """
31
+ self._server = MCPServer(name=name, version=version)
32
+ self._client = MCPClient()
33
+ self._running = False
34
+ self._server_task: Optional[asyncio.Task] = None
35
+
36
+ @property
37
+ def server(self) -> MCPServer:
38
+ """Get the local MCP server"""
39
+ return self._server
40
+
41
+ @property
42
+ def client(self) -> MCPClient:
43
+ """Get the MCP client"""
44
+ return self._client
45
+
46
+ @property
47
+ def is_running(self) -> bool:
48
+ """Check if the server is running"""
49
+ return self._running
50
+
51
+ # =========================================================================
52
+ # Server Management
53
+ # =========================================================================
54
+
55
+ def register_tool(
56
+ self,
57
+ name: str,
58
+ description: str,
59
+ handler: Callable,
60
+ parameters: Optional[List[MCPToolParameter]] = None
61
+ ) -> None:
62
+ """Register a tool with the local server
63
+
64
+ Args:
65
+ name: Tool name
66
+ description: Tool description
67
+ handler: Tool handler function
68
+ parameters: Tool parameters
69
+ """
70
+ self._server.register_tool(name, description, handler, parameters)
71
+
72
+ def register_resource(
73
+ self,
74
+ uri: str,
75
+ name: str,
76
+ description: str = "",
77
+ mime_type: Optional[str] = None
78
+ ) -> None:
79
+ """Register a resource with the local server
80
+
81
+ Args:
82
+ uri: Resource URI
83
+ name: Resource name
84
+ description: Resource description
85
+ mime_type: MIME type
86
+ """
87
+ self._server.register_resource(uri, name, description, mime_type)
88
+
89
+ def register_prompt(
90
+ self,
91
+ name: str,
92
+ description: str,
93
+ arguments: Optional[List[Dict]] = None
94
+ ) -> None:
95
+ """Register a prompt template
96
+
97
+ Args:
98
+ name: Prompt name
99
+ description: Prompt description
100
+ arguments: Prompt arguments
101
+ """
102
+ self._server.register_prompt(name, description, arguments)
103
+
104
+ def setup_default_tools(self) -> None:
105
+ """Set up default NC1709 tools on the server"""
106
+ self._server.create_default_tools()
107
+
108
+ async def start_server(self) -> None:
109
+ """Start the MCP server"""
110
+ if self._running:
111
+ return
112
+
113
+ self._running = True
114
+ self._server_task = asyncio.create_task(self._server.run_stdio())
115
+
116
+ async def stop_server(self) -> None:
117
+ """Stop the MCP server"""
118
+ if not self._running:
119
+ return
120
+
121
+ self._running = False
122
+ if self._server_task:
123
+ self._server_task.cancel()
124
+ try:
125
+ await self._server_task
126
+ except asyncio.CancelledError:
127
+ pass
128
+ self._server_task = None
129
+
130
+ # =========================================================================
131
+ # Client Management
132
+ # =========================================================================
133
+
134
+ async def connect_server(
135
+ self,
136
+ name: str,
137
+ command: str,
138
+ args: Optional[List[str]] = None,
139
+ env: Optional[Dict[str, str]] = None
140
+ ) -> bool:
141
+ """Connect to an external MCP server
142
+
143
+ Args:
144
+ name: Server name
145
+ command: Command to start the server
146
+ args: Command arguments
147
+ env: Environment variables
148
+
149
+ Returns:
150
+ True if connected successfully
151
+ """
152
+ return await self._client.connect(name, command, args, env)
153
+
154
+ async def disconnect_server(self, name: str) -> bool:
155
+ """Disconnect from an external MCP server
156
+
157
+ Args:
158
+ name: Server name
159
+
160
+ Returns:
161
+ True if disconnected
162
+ """
163
+ return await self._client.disconnect(name)
164
+
165
+ async def disconnect_all_servers(self) -> None:
166
+ """Disconnect from all external servers"""
167
+ await self._client.disconnect_all()
168
+
169
+ async def auto_discover_servers(self, config_path: Optional[str] = None) -> int:
170
+ """Auto-discover and connect to MCP servers from config
171
+
172
+ Args:
173
+ config_path: Path to MCP config file
174
+
175
+ Returns:
176
+ Number of servers connected
177
+ """
178
+ return await self._client.auto_discover(config_path)
179
+
180
+ # =========================================================================
181
+ # Tool Operations
182
+ # =========================================================================
183
+
184
+ def get_local_tools(self) -> List[MCPTool]:
185
+ """Get tools registered on the local server
186
+
187
+ Returns:
188
+ List of local tools
189
+ """
190
+ return list(self._server._tools.values())
191
+
192
+ def get_remote_tools(self, server_name: Optional[str] = None) -> List[MCPTool]:
193
+ """Get tools from connected servers
194
+
195
+ Args:
196
+ server_name: Filter by server (None for all)
197
+
198
+ Returns:
199
+ List of remote tools
200
+ """
201
+ return self._client.get_tools(server_name)
202
+
203
+ def get_all_tools(self) -> Dict[str, List[MCPTool]]:
204
+ """Get all available tools (local and remote)
205
+
206
+ Returns:
207
+ Dict with 'local' and 'remote' tool lists
208
+ """
209
+ return {
210
+ "local": self.get_local_tools(),
211
+ "remote": self.get_remote_tools()
212
+ }
213
+
214
+ async def call_remote_tool(
215
+ self,
216
+ server_name: str,
217
+ tool_name: str,
218
+ arguments: Optional[Dict[str, Any]] = None
219
+ ) -> Dict[str, Any]:
220
+ """Call a tool on a remote server
221
+
222
+ Args:
223
+ server_name: Server name
224
+ tool_name: Tool name
225
+ arguments: Tool arguments
226
+
227
+ Returns:
228
+ Tool result
229
+ """
230
+ return await self._client.call_tool(server_name, tool_name, arguments)
231
+
232
+ async def call_tool(
233
+ self,
234
+ tool_name: str,
235
+ arguments: Optional[Dict[str, Any]] = None,
236
+ server_name: Optional[str] = None
237
+ ) -> Dict[str, Any]:
238
+ """Call a tool (local or remote)
239
+
240
+ Args:
241
+ tool_name: Tool name
242
+ arguments: Tool arguments
243
+ server_name: Server name (None for local)
244
+
245
+ Returns:
246
+ Tool result
247
+ """
248
+ if server_name:
249
+ return await self.call_remote_tool(server_name, tool_name, arguments)
250
+
251
+ # Call local tool
252
+ if tool_name not in self._server._tools:
253
+ return {"error": f"Tool not found: {tool_name}"}
254
+
255
+ tool = self._server._tools[tool_name]
256
+ if tool.handler is None:
257
+ return {"error": f"Tool {tool_name} has no handler"}
258
+
259
+ try:
260
+ if asyncio.iscoroutinefunction(tool.handler):
261
+ result = await tool.handler(**(arguments or {}))
262
+ else:
263
+ result = tool.handler(**(arguments or {}))
264
+
265
+ if isinstance(result, ToolResult):
266
+ return {
267
+ "content": result.content,
268
+ "isError": result.is_error
269
+ }
270
+ elif isinstance(result, str):
271
+ return {
272
+ "content": [{"type": "text", "text": result}],
273
+ "isError": False
274
+ }
275
+ elif isinstance(result, dict):
276
+ return result
277
+ else:
278
+ return {
279
+ "content": [{"type": "text", "text": str(result)}],
280
+ "isError": False
281
+ }
282
+ except Exception as e:
283
+ return {"error": str(e)}
284
+
285
+ # =========================================================================
286
+ # Resource Operations
287
+ # =========================================================================
288
+
289
+ def get_local_resources(self) -> List[MCPResource]:
290
+ """Get resources registered on the local server
291
+
292
+ Returns:
293
+ List of local resources
294
+ """
295
+ return list(self._server._resources.values())
296
+
297
+ def get_remote_resources(self, server_name: Optional[str] = None) -> List[MCPResource]:
298
+ """Get resources from connected servers
299
+
300
+ Args:
301
+ server_name: Filter by server (None for all)
302
+
303
+ Returns:
304
+ List of remote resources
305
+ """
306
+ return self._client.get_resources(server_name)
307
+
308
+ def get_all_resources(self) -> Dict[str, List[MCPResource]]:
309
+ """Get all available resources (local and remote)
310
+
311
+ Returns:
312
+ Dict with 'local' and 'remote' resource lists
313
+ """
314
+ return {
315
+ "local": self.get_local_resources(),
316
+ "remote": self.get_remote_resources()
317
+ }
318
+
319
+ async def read_remote_resource(
320
+ self,
321
+ server_name: str,
322
+ uri: str
323
+ ) -> Dict[str, Any]:
324
+ """Read a resource from a remote server
325
+
326
+ Args:
327
+ server_name: Server name
328
+ uri: Resource URI
329
+
330
+ Returns:
331
+ Resource contents
332
+ """
333
+ return await self._client.read_resource(server_name, uri)
334
+
335
+ # =========================================================================
336
+ # Status and Info
337
+ # =========================================================================
338
+
339
+ def list_connected_servers(self) -> List[Dict[str, Any]]:
340
+ """List all connected external servers
341
+
342
+ Returns:
343
+ List of server info dicts
344
+ """
345
+ return self._client.list_servers()
346
+
347
+ def get_status(self) -> Dict[str, Any]:
348
+ """Get overall MCP status
349
+
350
+ Returns:
351
+ Status information
352
+ """
353
+ return {
354
+ "server": {
355
+ "name": self._server.name,
356
+ "version": self._server.version,
357
+ "running": self._running,
358
+ "tools": len(self._server._tools),
359
+ "resources": len(self._server._resources),
360
+ "prompts": len(self._server._prompts)
361
+ },
362
+ "client": {
363
+ "connected_servers": len(self._client._servers),
364
+ "servers": self.list_connected_servers()
365
+ }
366
+ }
367
+
368
+ # =========================================================================
369
+ # Cleanup
370
+ # =========================================================================
371
+
372
+ async def shutdown(self) -> None:
373
+ """Shutdown all MCP connections"""
374
+ await self.stop_server()
375
+ await self.disconnect_all_servers()
376
+
377
+ async def __aenter__(self) -> "MCPManager":
378
+ """Async context manager entry"""
379
+ return self
380
+
381
+ async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
382
+ """Async context manager exit"""
383
+ await self.shutdown()
384
+
385
+
386
+ # Convenience function to create a configured manager
387
+ def create_mcp_manager(
388
+ name: str = "nc1709",
389
+ version: str = "1.0.0",
390
+ with_default_tools: bool = True
391
+ ) -> MCPManager:
392
+ """Create and configure an MCP manager
393
+
394
+ Args:
395
+ name: Server name
396
+ version: Server version
397
+ with_default_tools: Whether to register default tools
398
+
399
+ Returns:
400
+ Configured MCPManager instance
401
+ """
402
+ manager = MCPManager(name=name, version=version)
403
+
404
+ if with_default_tools:
405
+ manager.setup_default_tools()
406
+
407
+ return manager
nc1709/mcp/protocol.py ADDED
@@ -0,0 +1,210 @@
1
+ """
2
+ MCP Protocol Definitions
3
+ Implements the Model Context Protocol message types and structures
4
+ """
5
+ from dataclasses import dataclass, field, asdict
6
+ from typing import List, Dict, Any, Optional, Union
7
+ from enum import Enum
8
+ import json
9
+
10
+
11
+ class MCPMessageType(Enum):
12
+ """MCP message types"""
13
+ # Requests
14
+ INITIALIZE = "initialize"
15
+ LIST_TOOLS = "tools/list"
16
+ CALL_TOOL = "tools/call"
17
+ LIST_RESOURCES = "resources/list"
18
+ READ_RESOURCE = "resources/read"
19
+ LIST_PROMPTS = "prompts/list"
20
+ GET_PROMPT = "prompts/get"
21
+
22
+ # Responses
23
+ RESULT = "result"
24
+ ERROR = "error"
25
+
26
+ # Notifications
27
+ NOTIFICATION = "notification"
28
+
29
+
30
+ @dataclass
31
+ class MCPMessage:
32
+ """Base MCP message structure"""
33
+ jsonrpc: str = "2.0"
34
+ id: Optional[Union[str, int]] = None
35
+ method: Optional[str] = None
36
+ params: Optional[Dict[str, Any]] = None
37
+ result: Optional[Any] = None
38
+ error: Optional[Dict[str, Any]] = None
39
+
40
+ def to_dict(self) -> Dict[str, Any]:
41
+ """Convert to dictionary, excluding None values"""
42
+ data = {"jsonrpc": self.jsonrpc}
43
+ if self.id is not None:
44
+ data["id"] = self.id
45
+ if self.method is not None:
46
+ data["method"] = self.method
47
+ if self.params is not None:
48
+ data["params"] = self.params
49
+ if self.result is not None:
50
+ data["result"] = self.result
51
+ if self.error is not None:
52
+ data["error"] = self.error
53
+ return data
54
+
55
+ def to_json(self) -> str:
56
+ """Convert to JSON string"""
57
+ return json.dumps(self.to_dict())
58
+
59
+ @classmethod
60
+ def from_json(cls, data: str) -> "MCPMessage":
61
+ """Parse from JSON string"""
62
+ parsed = json.loads(data)
63
+ return cls(**parsed)
64
+
65
+ @classmethod
66
+ def request(cls, id: Union[str, int], method: str, params: Optional[Dict] = None) -> "MCPMessage":
67
+ """Create a request message"""
68
+ return cls(id=id, method=method, params=params)
69
+
70
+ @classmethod
71
+ def response(cls, id: Union[str, int], result: Any) -> "MCPMessage":
72
+ """Create a success response"""
73
+ return cls(id=id, result=result)
74
+
75
+ @classmethod
76
+ def error_response(cls, id: Union[str, int], code: int, message: str, data: Any = None) -> "MCPMessage":
77
+ """Create an error response"""
78
+ error = {"code": code, "message": message}
79
+ if data is not None:
80
+ error["data"] = data
81
+ return cls(id=id, error=error)
82
+
83
+
84
+ @dataclass
85
+ class MCPToolParameter:
86
+ """Parameter definition for an MCP tool"""
87
+ name: str
88
+ type: str # "string", "number", "boolean", "array", "object"
89
+ description: str = ""
90
+ required: bool = False
91
+ default: Any = None
92
+
93
+ def to_json_schema(self) -> Dict[str, Any]:
94
+ """Convert to JSON Schema format"""
95
+ schema = {
96
+ "type": self.type,
97
+ "description": self.description
98
+ }
99
+ if self.default is not None:
100
+ schema["default"] = self.default
101
+ return schema
102
+
103
+
104
+ @dataclass
105
+ class MCPTool:
106
+ """Represents an MCP tool (capability)"""
107
+ name: str
108
+ description: str
109
+ parameters: List[MCPToolParameter] = field(default_factory=list)
110
+ handler: Optional[Any] = None # Callable for local tools
111
+
112
+ def to_dict(self) -> Dict[str, Any]:
113
+ """Convert to MCP tool format"""
114
+ properties = {}
115
+ required = []
116
+
117
+ for param in self.parameters:
118
+ properties[param.name] = param.to_json_schema()
119
+ if param.required:
120
+ required.append(param.name)
121
+
122
+ return {
123
+ "name": self.name,
124
+ "description": self.description,
125
+ "inputSchema": {
126
+ "type": "object",
127
+ "properties": properties,
128
+ "required": required
129
+ }
130
+ }
131
+
132
+
133
+ @dataclass
134
+ class MCPResource:
135
+ """Represents an MCP resource"""
136
+ uri: str
137
+ name: str
138
+ description: str = ""
139
+ mimeType: Optional[str] = None
140
+
141
+ def to_dict(self) -> Dict[str, Any]:
142
+ """Convert to MCP resource format"""
143
+ data = {
144
+ "uri": self.uri,
145
+ "name": self.name,
146
+ "description": self.description
147
+ }
148
+ if self.mimeType:
149
+ data["mimeType"] = self.mimeType
150
+ return data
151
+
152
+
153
+ @dataclass
154
+ class MCPPrompt:
155
+ """Represents an MCP prompt template"""
156
+ name: str
157
+ description: str
158
+ arguments: List[Dict[str, Any]] = field(default_factory=list)
159
+
160
+ def to_dict(self) -> Dict[str, Any]:
161
+ """Convert to MCP prompt format"""
162
+ return {
163
+ "name": self.name,
164
+ "description": self.description,
165
+ "arguments": self.arguments
166
+ }
167
+
168
+
169
+ @dataclass
170
+ class MCPServerInfo:
171
+ """MCP server capabilities and information"""
172
+ name: str
173
+ version: str
174
+ capabilities: Dict[str, Any] = field(default_factory=dict)
175
+
176
+ def to_dict(self) -> Dict[str, Any]:
177
+ return {
178
+ "name": self.name,
179
+ "version": self.version,
180
+ "capabilities": self.capabilities
181
+ }
182
+
183
+
184
+ @dataclass
185
+ class MCPClientInfo:
186
+ """MCP client information"""
187
+ name: str
188
+ version: str
189
+
190
+ def to_dict(self) -> Dict[str, Any]:
191
+ return {
192
+ "name": self.name,
193
+ "version": self.version
194
+ }
195
+
196
+
197
+ # Error codes following JSON-RPC 2.0
198
+ class MCPErrorCode:
199
+ """Standard MCP error codes"""
200
+ PARSE_ERROR = -32700
201
+ INVALID_REQUEST = -32600
202
+ METHOD_NOT_FOUND = -32601
203
+ INVALID_PARAMS = -32602
204
+ INTERNAL_ERROR = -32603
205
+
206
+ # Custom MCP errors
207
+ TOOL_NOT_FOUND = -32000
208
+ RESOURCE_NOT_FOUND = -32001
209
+ PERMISSION_DENIED = -32002
210
+ EXECUTION_ERROR = -32003