devduck 0.3.0__py3-none-any.whl → 0.4.1__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 devduck might be problematic. Click here for more details.
- devduck/__init__.py +100 -197
- devduck/_version.py +2 -2
- devduck/tools/mcp_server.py +34 -6
- devduck/tools/system_prompt.py +485 -0
- devduck-0.4.1.dist-info/METADATA +283 -0
- {devduck-0.3.0.dist-info → devduck-0.4.1.dist-info}/RECORD +10 -9
- devduck-0.3.0.dist-info/METADATA +0 -152
- {devduck-0.3.0.dist-info → devduck-0.4.1.dist-info}/WHEEL +0 -0
- {devduck-0.3.0.dist-info → devduck-0.4.1.dist-info}/entry_points.txt +0 -0
- {devduck-0.3.0.dist-info → devduck-0.4.1.dist-info}/licenses/LICENSE +0 -0
- {devduck-0.3.0.dist-info → devduck-0.4.1.dist-info}/top_level.txt +0 -0
devduck/__init__.py
CHANGED
|
@@ -126,168 +126,6 @@ def get_own_source_code():
|
|
|
126
126
|
except Exception as e:
|
|
127
127
|
return f"Error reading own source code: {e}"
|
|
128
128
|
|
|
129
|
-
|
|
130
|
-
# 🛠️ System prompt tool (with .prompt file persistence)
|
|
131
|
-
def system_prompt_tool(
|
|
132
|
-
action: str,
|
|
133
|
-
prompt: str | None = None,
|
|
134
|
-
context: str | None = None,
|
|
135
|
-
variable_name: str = "SYSTEM_PROMPT",
|
|
136
|
-
) -> Dict[str, Any]:
|
|
137
|
-
"""
|
|
138
|
-
Manage the agent's system prompt dynamically with file persistence.
|
|
139
|
-
|
|
140
|
-
Args:
|
|
141
|
-
action: "view", "update", "add_context", or "reset"
|
|
142
|
-
prompt: New system prompt text (required for "update")
|
|
143
|
-
context: Additional context to prepend (for "add_context")
|
|
144
|
-
variable_name: Environment variable name (default: SYSTEM_PROMPT)
|
|
145
|
-
|
|
146
|
-
Returns:
|
|
147
|
-
Dict with status and content
|
|
148
|
-
"""
|
|
149
|
-
from pathlib import Path
|
|
150
|
-
import tempfile
|
|
151
|
-
|
|
152
|
-
def _get_prompt_file_path() -> Path:
|
|
153
|
-
"""Get the .prompt file path in temp directory."""
|
|
154
|
-
temp_dir = Path(tempfile.gettempdir()) / ".devduck"
|
|
155
|
-
temp_dir.mkdir(exist_ok=True, mode=0o700) # Create with restrictive permissions
|
|
156
|
-
return temp_dir / ".prompt"
|
|
157
|
-
|
|
158
|
-
def _write_prompt_file(prompt_text: str) -> None:
|
|
159
|
-
"""Write prompt to .prompt file in temp directory."""
|
|
160
|
-
prompt_file = _get_prompt_file_path()
|
|
161
|
-
try:
|
|
162
|
-
# Create file with restrictive permissions
|
|
163
|
-
with open(
|
|
164
|
-
prompt_file,
|
|
165
|
-
"w",
|
|
166
|
-
encoding="utf-8",
|
|
167
|
-
opener=lambda path, flags: os.open(path, flags, 0o600),
|
|
168
|
-
) as f:
|
|
169
|
-
f.write(prompt_text)
|
|
170
|
-
except (OSError, PermissionError):
|
|
171
|
-
try:
|
|
172
|
-
prompt_file.write_text(prompt_text, encoding="utf-8")
|
|
173
|
-
prompt_file.chmod(0o600)
|
|
174
|
-
except (OSError, PermissionError):
|
|
175
|
-
prompt_file.write_text(prompt_text, encoding="utf-8")
|
|
176
|
-
|
|
177
|
-
def _get_system_prompt(var_name: str) -> str:
|
|
178
|
-
"""Get current system prompt from environment variable."""
|
|
179
|
-
return os.environ.get(var_name, "")
|
|
180
|
-
|
|
181
|
-
def _update_system_prompt(new_prompt: str, var_name: str) -> None:
|
|
182
|
-
"""Update system prompt in both environment and .prompt file."""
|
|
183
|
-
os.environ[var_name] = new_prompt
|
|
184
|
-
if var_name == "SYSTEM_PROMPT":
|
|
185
|
-
_write_prompt_file(new_prompt)
|
|
186
|
-
|
|
187
|
-
try:
|
|
188
|
-
if action == "view":
|
|
189
|
-
current = _get_system_prompt(variable_name)
|
|
190
|
-
return {
|
|
191
|
-
"status": "success",
|
|
192
|
-
"content": [
|
|
193
|
-
{"text": f"Current system prompt from {variable_name}:{current}"}
|
|
194
|
-
],
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
elif action == "update":
|
|
198
|
-
if not prompt:
|
|
199
|
-
return {
|
|
200
|
-
"status": "error",
|
|
201
|
-
"content": [
|
|
202
|
-
{"text": "Error: prompt parameter required for update action"}
|
|
203
|
-
],
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
_update_system_prompt(prompt, variable_name)
|
|
207
|
-
|
|
208
|
-
if variable_name == "SYSTEM_PROMPT":
|
|
209
|
-
message = f"System prompt updated (env: {variable_name}, file: .prompt)"
|
|
210
|
-
else:
|
|
211
|
-
message = f"System prompt updated (env: {variable_name})"
|
|
212
|
-
|
|
213
|
-
return {"status": "success", "content": [{"text": message}]}
|
|
214
|
-
|
|
215
|
-
elif action == "add_context":
|
|
216
|
-
if not context:
|
|
217
|
-
return {
|
|
218
|
-
"status": "error",
|
|
219
|
-
"content": [
|
|
220
|
-
{
|
|
221
|
-
"text": "Error: context parameter required for add_context action"
|
|
222
|
-
}
|
|
223
|
-
],
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
current = _get_system_prompt(variable_name)
|
|
227
|
-
new_prompt = f"{current} {context}" if current else context
|
|
228
|
-
_update_system_prompt(new_prompt, variable_name)
|
|
229
|
-
|
|
230
|
-
if variable_name == "SYSTEM_PROMPT":
|
|
231
|
-
message = f"Context added to system prompt (env: {variable_name}, file: .prompt)"
|
|
232
|
-
else:
|
|
233
|
-
message = f"Context added to system prompt (env: {variable_name})"
|
|
234
|
-
|
|
235
|
-
return {"status": "success", "content": [{"text": message}]}
|
|
236
|
-
|
|
237
|
-
elif action == "reset":
|
|
238
|
-
os.environ.pop(variable_name, None)
|
|
239
|
-
|
|
240
|
-
if variable_name == "SYSTEM_PROMPT":
|
|
241
|
-
prompt_file = _get_prompt_file_path()
|
|
242
|
-
if prompt_file.exists():
|
|
243
|
-
try:
|
|
244
|
-
prompt_file.unlink()
|
|
245
|
-
except (OSError, PermissionError):
|
|
246
|
-
pass
|
|
247
|
-
message = (
|
|
248
|
-
f"System prompt reset (env: {variable_name}, file: .prompt cleared)"
|
|
249
|
-
)
|
|
250
|
-
else:
|
|
251
|
-
message = f"System prompt reset (env: {variable_name})"
|
|
252
|
-
|
|
253
|
-
return {"status": "success", "content": [{"text": message}]}
|
|
254
|
-
|
|
255
|
-
elif action == "get":
|
|
256
|
-
# Backward compatibility
|
|
257
|
-
current = _get_system_prompt(variable_name)
|
|
258
|
-
return {
|
|
259
|
-
"status": "success",
|
|
260
|
-
"content": [{"text": f"System prompt: {current}"}],
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
elif action == "set":
|
|
264
|
-
# Backward compatibility
|
|
265
|
-
if prompt is None:
|
|
266
|
-
return {"status": "error", "content": [{"text": "No prompt provided"}]}
|
|
267
|
-
|
|
268
|
-
if context:
|
|
269
|
-
prompt = f"{context} {prompt}"
|
|
270
|
-
|
|
271
|
-
_update_system_prompt(prompt, variable_name)
|
|
272
|
-
return {
|
|
273
|
-
"status": "success",
|
|
274
|
-
"content": [{"text": "System prompt updated successfully"}],
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
else:
|
|
278
|
-
return {
|
|
279
|
-
"status": "error",
|
|
280
|
-
"content": [
|
|
281
|
-
{
|
|
282
|
-
"text": f"Unknown action '{action}'. Valid: view, update, add_context, reset"
|
|
283
|
-
}
|
|
284
|
-
],
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
except Exception as e:
|
|
288
|
-
return {"status": "error", "content": [{"text": f"Error: {str(e)}"}]}
|
|
289
|
-
|
|
290
|
-
|
|
291
129
|
def view_logs_tool(
|
|
292
130
|
action: str = "view",
|
|
293
131
|
lines: int = 100,
|
|
@@ -661,6 +499,7 @@ class DevDuck:
|
|
|
661
499
|
use_github,
|
|
662
500
|
create_subagent,
|
|
663
501
|
store_in_kb,
|
|
502
|
+
system_prompt,
|
|
664
503
|
)
|
|
665
504
|
|
|
666
505
|
core_tools.extend(
|
|
@@ -672,34 +511,39 @@ class DevDuck:
|
|
|
672
511
|
use_github,
|
|
673
512
|
create_subagent,
|
|
674
513
|
store_in_kb,
|
|
514
|
+
system_prompt
|
|
675
515
|
]
|
|
676
516
|
)
|
|
677
517
|
except ImportError as e:
|
|
678
518
|
logger.warning(f"devduck.tools import failed: {e}")
|
|
679
519
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
520
|
+
# Skip fun tools in --mcp mode (they're not needed for MCP server)
|
|
521
|
+
if "--mcp" not in sys.argv:
|
|
522
|
+
try:
|
|
523
|
+
from strands_fun_tools import (
|
|
524
|
+
listen,
|
|
525
|
+
cursor,
|
|
526
|
+
clipboard,
|
|
527
|
+
screen_reader,
|
|
528
|
+
yolo_vision,
|
|
529
|
+
)
|
|
688
530
|
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
531
|
+
core_tools.extend(
|
|
532
|
+
[listen, cursor, clipboard, screen_reader, yolo_vision]
|
|
533
|
+
)
|
|
534
|
+
except ImportError:
|
|
535
|
+
logger.info(
|
|
536
|
+
"strands-fun-tools not installed - vision/audio tools unavailable (install with: pip install devduck[all])"
|
|
537
|
+
)
|
|
538
|
+
else:
|
|
539
|
+
logger.info("--mcp mode: skipping vision/audio tools")
|
|
696
540
|
|
|
697
541
|
try:
|
|
698
542
|
from strands_tools import (
|
|
699
543
|
shell,
|
|
700
544
|
editor,
|
|
701
545
|
calculator,
|
|
702
|
-
python_repl,
|
|
546
|
+
# python_repl,
|
|
703
547
|
image_reader,
|
|
704
548
|
use_agent,
|
|
705
549
|
load_tool,
|
|
@@ -713,7 +557,7 @@ class DevDuck:
|
|
|
713
557
|
shell,
|
|
714
558
|
editor,
|
|
715
559
|
calculator,
|
|
716
|
-
python_repl,
|
|
560
|
+
# python_repl,
|
|
717
561
|
image_reader,
|
|
718
562
|
use_agent,
|
|
719
563
|
load_tool,
|
|
@@ -727,17 +571,6 @@ class DevDuck:
|
|
|
727
571
|
"strands-agents-tools not installed - core tools unavailable (install with: pip install devduck[all])"
|
|
728
572
|
)
|
|
729
573
|
|
|
730
|
-
# Wrap system_prompt_tool with @tool decorator
|
|
731
|
-
@tool
|
|
732
|
-
def system_prompt(
|
|
733
|
-
action: str,
|
|
734
|
-
prompt: str = None,
|
|
735
|
-
context: str = None,
|
|
736
|
-
variable_name: str = "SYSTEM_PROMPT",
|
|
737
|
-
) -> Dict[str, Any]:
|
|
738
|
-
"""Manage agent system prompt dynamically."""
|
|
739
|
-
return system_prompt_tool(action, prompt, context, variable_name)
|
|
740
|
-
|
|
741
574
|
# Wrap view_logs_tool with @tool decorator
|
|
742
575
|
@tool
|
|
743
576
|
def view_logs(
|
|
@@ -749,7 +582,7 @@ class DevDuck:
|
|
|
749
582
|
return view_logs_tool(action, lines, pattern)
|
|
750
583
|
|
|
751
584
|
# Add built-in tools to the toolset
|
|
752
|
-
core_tools.extend([
|
|
585
|
+
core_tools.extend([view_logs])
|
|
753
586
|
|
|
754
587
|
# Assign tools
|
|
755
588
|
self.tools = core_tools
|
|
@@ -976,9 +809,20 @@ def weather(action: str, location: str = None) -> Dict[str, Any]:
|
|
|
976
809
|
```
|
|
977
810
|
|
|
978
811
|
## System Prompt Management:
|
|
979
|
-
-
|
|
980
|
-
-
|
|
981
|
-
-
|
|
812
|
+
- **View**: system_prompt(action='view') - See current prompt
|
|
813
|
+
- **Update Local**: system_prompt(action='update', prompt='new text') - Updates env var + .prompt file
|
|
814
|
+
- **Update GitHub**: system_prompt(action='update', prompt='text', repository='cagataycali/devduck') - Syncs to repo variables
|
|
815
|
+
- **Variable Name**: system_prompt(action='update', prompt='text', variable_name='CUSTOM_PROMPT') - Use custom var
|
|
816
|
+
- **Add Context**: system_prompt(action='add_context', context='new learning') - Append without replacing
|
|
817
|
+
|
|
818
|
+
### 🧠 Self-Improvement Pattern:
|
|
819
|
+
When you learn something valuable during conversations:
|
|
820
|
+
1. Identify the new insight or pattern
|
|
821
|
+
2. Use system_prompt(action='add_context', context='...') to append it
|
|
822
|
+
3. Sync to GitHub: system_prompt(action='update', prompt=new_full_prompt, repository='owner/repo')
|
|
823
|
+
4. New learnings persist across sessions via SYSTEM_PROMPT env var
|
|
824
|
+
|
|
825
|
+
**Repository Integration**: Set repository='cagataycali/devduck' to sync prompts across deployments
|
|
982
826
|
|
|
983
827
|
## Shell Commands:
|
|
984
828
|
- Prefix with ! to execute shell commands directly
|
|
@@ -1267,7 +1111,13 @@ def weather(action: str, location: str = None) -> Dict[str, Any]:
|
|
|
1267
1111
|
|
|
1268
1112
|
# 🦆 Auto-initialize when imported
|
|
1269
1113
|
# Check environment variables to control server configuration
|
|
1114
|
+
# Also check if --mcp flag is present to skip auto-starting servers
|
|
1270
1115
|
_auto_start = os.getenv("DEVDUCK_AUTO_START_SERVERS", "true").lower() == "true"
|
|
1116
|
+
|
|
1117
|
+
# Disable auto-start if --mcp flag is present (stdio mode)
|
|
1118
|
+
if "--mcp" in sys.argv:
|
|
1119
|
+
_auto_start = False
|
|
1120
|
+
|
|
1271
1121
|
_tcp_port = int(os.getenv("DEVDUCK_TCP_PORT", "9999"))
|
|
1272
1122
|
_ws_port = int(os.getenv("DEVDUCK_WS_PORT", "8080"))
|
|
1273
1123
|
_mcp_port = int(os.getenv("DEVDUCK_MCP_PORT", "8000"))
|
|
@@ -1510,9 +1360,20 @@ You have full access to your own source code for self-awareness and self-modific
|
|
|
1510
1360
|
- Full bidirectional communication
|
|
1511
1361
|
|
|
1512
1362
|
## System Prompt Management:
|
|
1513
|
-
-
|
|
1514
|
-
-
|
|
1515
|
-
-
|
|
1363
|
+
- **View**: system_prompt(action='view') - See current prompt
|
|
1364
|
+
- **Update Local**: system_prompt(action='update', prompt='new text') - Updates env var + .prompt file
|
|
1365
|
+
- **Update GitHub**: system_prompt(action='update', prompt='text', repository='cagataycali/devduck') - Syncs to repo variables
|
|
1366
|
+
- **Variable Name**: system_prompt(action='update', prompt='text', variable_name='CUSTOM_PROMPT') - Use custom var
|
|
1367
|
+
- **Add Context**: system_prompt(action='add_context', context='new learning') - Append without replacing
|
|
1368
|
+
|
|
1369
|
+
### 🧠 Self-Improvement Pattern:
|
|
1370
|
+
When you learn something valuable during conversations:
|
|
1371
|
+
1. Identify the new insight or pattern
|
|
1372
|
+
2. Use system_prompt(action='add_context', context='...') to append it
|
|
1373
|
+
3. Optionally sync to GitHub: system_prompt(action='update', prompt=new_full_prompt, repository='owner/repo')
|
|
1374
|
+
4. New learnings persist across sessions via SYSTEM_PROMPT env var
|
|
1375
|
+
|
|
1376
|
+
**Repository Integration**: Set repository='cagataycali/devduck' to sync prompts across deployments
|
|
1516
1377
|
|
|
1517
1378
|
## Shell Commands:
|
|
1518
1379
|
- Prefix with ! to execute shell commands directly
|
|
@@ -1561,15 +1422,33 @@ def cli():
|
|
|
1561
1422
|
Examples:
|
|
1562
1423
|
devduck # Start interactive mode
|
|
1563
1424
|
devduck "your query here" # One-shot query
|
|
1425
|
+
devduck --mcp # MCP stdio mode (for Claude Desktop)
|
|
1564
1426
|
devduck --tcp-port 9000 # Custom TCP port
|
|
1565
1427
|
devduck --no-tcp --no-ws # Disable TCP and WebSocket
|
|
1566
1428
|
devduck --mcp-port 3000 # Custom MCP port
|
|
1429
|
+
|
|
1430
|
+
Claude Desktop Config:
|
|
1431
|
+
{
|
|
1432
|
+
"mcpServers": {
|
|
1433
|
+
"devduck": {
|
|
1434
|
+
"command": "uvx",
|
|
1435
|
+
"args": ["devduck", "--mcp"]
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1567
1439
|
""",
|
|
1568
1440
|
)
|
|
1569
1441
|
|
|
1570
1442
|
# Query argument
|
|
1571
1443
|
parser.add_argument("query", nargs="*", help="Query to send to the agent")
|
|
1572
1444
|
|
|
1445
|
+
# MCP stdio mode flag
|
|
1446
|
+
parser.add_argument(
|
|
1447
|
+
"--mcp",
|
|
1448
|
+
action="store_true",
|
|
1449
|
+
help="Start MCP server in stdio mode (for Claude Desktop integration)",
|
|
1450
|
+
)
|
|
1451
|
+
|
|
1573
1452
|
# Server configuration
|
|
1574
1453
|
parser.add_argument(
|
|
1575
1454
|
"--tcp-port", type=int, default=9999, help="TCP server port (default: 9999)"
|
|
@@ -1601,6 +1480,30 @@ Examples:
|
|
|
1601
1480
|
|
|
1602
1481
|
logger.info("CLI mode started")
|
|
1603
1482
|
|
|
1483
|
+
# Handle --mcp flag for stdio mode
|
|
1484
|
+
if args.mcp:
|
|
1485
|
+
logger.info("Starting MCP server in stdio mode (blocking, foreground)")
|
|
1486
|
+
print("🦆 Starting MCP stdio server...", file=sys.stderr)
|
|
1487
|
+
|
|
1488
|
+
# Don't auto-start HTTP/TCP/WS servers for stdio mode
|
|
1489
|
+
if devduck.agent:
|
|
1490
|
+
try:
|
|
1491
|
+
# Start MCP server in stdio mode - this BLOCKS until terminated
|
|
1492
|
+
devduck.agent.tool.mcp_server(
|
|
1493
|
+
action="start",
|
|
1494
|
+
transport="stdio",
|
|
1495
|
+
expose_agent=True,
|
|
1496
|
+
agent=devduck.agent,
|
|
1497
|
+
)
|
|
1498
|
+
except Exception as e:
|
|
1499
|
+
logger.error(f"Failed to start MCP stdio server: {e}")
|
|
1500
|
+
print(f"🦆 Error: {e}", file=sys.stderr)
|
|
1501
|
+
sys.exit(1)
|
|
1502
|
+
else:
|
|
1503
|
+
print("🦆 Agent not available", file=sys.stderr)
|
|
1504
|
+
sys.exit(1)
|
|
1505
|
+
return
|
|
1506
|
+
|
|
1604
1507
|
if args.query:
|
|
1605
1508
|
query = " ".join(args.query)
|
|
1606
1509
|
logger.info(f"CLI query: {query}")
|
devduck/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0,
|
|
31
|
+
__version__ = version = '0.4.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 4, 1)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
devduck/tools/mcp_server.py
CHANGED
|
@@ -190,9 +190,11 @@ def _start_mcp_server(
|
|
|
190
190
|
agent_invoke_tool = types.Tool(
|
|
191
191
|
name="devduck",
|
|
192
192
|
description=(
|
|
193
|
-
"Invoke
|
|
194
|
-
"
|
|
195
|
-
"
|
|
193
|
+
"Invoke a FULL DevDuck instance with complete capabilities. "
|
|
194
|
+
"Each invocation creates a fresh DevDuck agent with self-healing, "
|
|
195
|
+
"hot-reload, all tools, knowledge base integration, and system prompt building. "
|
|
196
|
+
"Use this for complex queries requiring reasoning, multi-tool orchestration, "
|
|
197
|
+
"or when you need the complete DevDuck experience via MCP."
|
|
196
198
|
),
|
|
197
199
|
inputSchema={
|
|
198
200
|
"type": "object",
|
|
@@ -228,7 +230,7 @@ def _start_mcp_server(
|
|
|
228
230
|
try:
|
|
229
231
|
logger.debug(f"call_tool: name={name}, arguments={arguments}")
|
|
230
232
|
|
|
231
|
-
# Handle agent invocation tool -
|
|
233
|
+
# Handle agent invocation tool - create a full DevDuck instance
|
|
232
234
|
if name == "devduck" and expose_agent:
|
|
233
235
|
prompt = arguments.get("prompt")
|
|
234
236
|
if not prompt:
|
|
@@ -241,8 +243,34 @@ def _start_mcp_server(
|
|
|
241
243
|
|
|
242
244
|
logger.debug(f"Invoking devduck with prompt: {prompt[:100]}...")
|
|
243
245
|
|
|
244
|
-
#
|
|
245
|
-
|
|
246
|
+
# Create a NEW DevDuck instance for this MCP invocation
|
|
247
|
+
# This gives full DevDuck power: self-healing, hot-reload, all tools, etc.
|
|
248
|
+
try:
|
|
249
|
+
from devduck import DevDuck
|
|
250
|
+
|
|
251
|
+
# Create fresh DevDuck instance (no auto-start to avoid recursion)
|
|
252
|
+
mcp_devduck = DevDuck(auto_start_servers=False)
|
|
253
|
+
mcp_agent = mcp_devduck.agent
|
|
254
|
+
|
|
255
|
+
if not mcp_agent:
|
|
256
|
+
return [
|
|
257
|
+
types.TextContent(
|
|
258
|
+
type="text",
|
|
259
|
+
text="❌ Error: Failed to create DevDuck instance",
|
|
260
|
+
)
|
|
261
|
+
]
|
|
262
|
+
|
|
263
|
+
# Execute with full DevDuck capabilities
|
|
264
|
+
result = mcp_agent(prompt)
|
|
265
|
+
|
|
266
|
+
except Exception as e:
|
|
267
|
+
logger.error(f"DevDuck creation failed: {e}", exc_info=True)
|
|
268
|
+
return [
|
|
269
|
+
types.TextContent(
|
|
270
|
+
type="text",
|
|
271
|
+
text=f"❌ Error creating DevDuck instance: {str(e)}",
|
|
272
|
+
)
|
|
273
|
+
]
|
|
246
274
|
|
|
247
275
|
# Extract text response from agent result
|
|
248
276
|
response_text = str(result)
|