PraisonAI 3.0.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.
- praisonai/__init__.py +54 -0
- praisonai/__main__.py +15 -0
- praisonai/acp/__init__.py +54 -0
- praisonai/acp/config.py +159 -0
- praisonai/acp/server.py +587 -0
- praisonai/acp/session.py +219 -0
- praisonai/adapters/__init__.py +50 -0
- praisonai/adapters/readers.py +395 -0
- praisonai/adapters/rerankers.py +315 -0
- praisonai/adapters/retrievers.py +394 -0
- praisonai/adapters/vector_stores.py +409 -0
- praisonai/agent_scheduler.py +337 -0
- praisonai/agents_generator.py +903 -0
- praisonai/api/call.py +292 -0
- praisonai/auto.py +1197 -0
- praisonai/capabilities/__init__.py +275 -0
- praisonai/capabilities/a2a.py +140 -0
- praisonai/capabilities/assistants.py +283 -0
- praisonai/capabilities/audio.py +320 -0
- praisonai/capabilities/batches.py +469 -0
- praisonai/capabilities/completions.py +336 -0
- praisonai/capabilities/container_files.py +155 -0
- praisonai/capabilities/containers.py +93 -0
- praisonai/capabilities/embeddings.py +158 -0
- praisonai/capabilities/files.py +467 -0
- praisonai/capabilities/fine_tuning.py +293 -0
- praisonai/capabilities/guardrails.py +182 -0
- praisonai/capabilities/images.py +330 -0
- praisonai/capabilities/mcp.py +190 -0
- praisonai/capabilities/messages.py +270 -0
- praisonai/capabilities/moderations.py +154 -0
- praisonai/capabilities/ocr.py +217 -0
- praisonai/capabilities/passthrough.py +204 -0
- praisonai/capabilities/rag.py +207 -0
- praisonai/capabilities/realtime.py +160 -0
- praisonai/capabilities/rerank.py +165 -0
- praisonai/capabilities/responses.py +266 -0
- praisonai/capabilities/search.py +109 -0
- praisonai/capabilities/skills.py +133 -0
- praisonai/capabilities/vector_store_files.py +334 -0
- praisonai/capabilities/vector_stores.py +304 -0
- praisonai/capabilities/videos.py +141 -0
- praisonai/chainlit_ui.py +304 -0
- praisonai/chat/__init__.py +106 -0
- praisonai/chat/app.py +125 -0
- praisonai/cli/__init__.py +26 -0
- praisonai/cli/app.py +213 -0
- praisonai/cli/commands/__init__.py +75 -0
- praisonai/cli/commands/acp.py +70 -0
- praisonai/cli/commands/completion.py +333 -0
- praisonai/cli/commands/config.py +166 -0
- praisonai/cli/commands/debug.py +142 -0
- praisonai/cli/commands/diag.py +55 -0
- praisonai/cli/commands/doctor.py +166 -0
- praisonai/cli/commands/environment.py +179 -0
- praisonai/cli/commands/lsp.py +112 -0
- praisonai/cli/commands/mcp.py +210 -0
- praisonai/cli/commands/profile.py +457 -0
- praisonai/cli/commands/run.py +228 -0
- praisonai/cli/commands/schedule.py +150 -0
- praisonai/cli/commands/serve.py +97 -0
- praisonai/cli/commands/session.py +212 -0
- praisonai/cli/commands/traces.py +145 -0
- praisonai/cli/commands/version.py +101 -0
- praisonai/cli/configuration/__init__.py +18 -0
- praisonai/cli/configuration/loader.py +353 -0
- praisonai/cli/configuration/paths.py +114 -0
- praisonai/cli/configuration/schema.py +164 -0
- praisonai/cli/features/__init__.py +268 -0
- praisonai/cli/features/acp.py +236 -0
- praisonai/cli/features/action_orchestrator.py +546 -0
- praisonai/cli/features/agent_scheduler.py +773 -0
- praisonai/cli/features/agent_tools.py +474 -0
- praisonai/cli/features/agents.py +375 -0
- praisonai/cli/features/at_mentions.py +471 -0
- praisonai/cli/features/auto_memory.py +182 -0
- praisonai/cli/features/autonomy_mode.py +490 -0
- praisonai/cli/features/background.py +356 -0
- praisonai/cli/features/base.py +168 -0
- praisonai/cli/features/capabilities.py +1326 -0
- praisonai/cli/features/checkpoints.py +338 -0
- praisonai/cli/features/code_intelligence.py +652 -0
- praisonai/cli/features/compaction.py +294 -0
- praisonai/cli/features/compare.py +534 -0
- praisonai/cli/features/cost_tracker.py +514 -0
- praisonai/cli/features/debug.py +810 -0
- praisonai/cli/features/deploy.py +517 -0
- praisonai/cli/features/diag.py +289 -0
- praisonai/cli/features/doctor/__init__.py +63 -0
- praisonai/cli/features/doctor/checks/__init__.py +24 -0
- praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
- praisonai/cli/features/doctor/checks/config_checks.py +366 -0
- praisonai/cli/features/doctor/checks/db_checks.py +366 -0
- praisonai/cli/features/doctor/checks/env_checks.py +543 -0
- praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
- praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
- praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
- praisonai/cli/features/doctor/checks/network_checks.py +251 -0
- praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
- praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
- praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
- praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
- praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
- praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
- praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
- praisonai/cli/features/doctor/engine.py +266 -0
- praisonai/cli/features/doctor/formatters.py +310 -0
- praisonai/cli/features/doctor/handler.py +397 -0
- praisonai/cli/features/doctor/models.py +264 -0
- praisonai/cli/features/doctor/registry.py +239 -0
- praisonai/cli/features/endpoints.py +1019 -0
- praisonai/cli/features/eval.py +560 -0
- praisonai/cli/features/external_agents.py +231 -0
- praisonai/cli/features/fast_context.py +410 -0
- praisonai/cli/features/flow_display.py +566 -0
- praisonai/cli/features/git_integration.py +651 -0
- praisonai/cli/features/guardrail.py +171 -0
- praisonai/cli/features/handoff.py +185 -0
- praisonai/cli/features/hooks.py +583 -0
- praisonai/cli/features/image.py +384 -0
- praisonai/cli/features/interactive_runtime.py +585 -0
- praisonai/cli/features/interactive_tools.py +380 -0
- praisonai/cli/features/interactive_tui.py +603 -0
- praisonai/cli/features/jobs.py +632 -0
- praisonai/cli/features/knowledge.py +531 -0
- praisonai/cli/features/lite.py +244 -0
- praisonai/cli/features/lsp_cli.py +225 -0
- praisonai/cli/features/mcp.py +169 -0
- praisonai/cli/features/message_queue.py +587 -0
- praisonai/cli/features/metrics.py +211 -0
- praisonai/cli/features/n8n.py +673 -0
- praisonai/cli/features/observability.py +293 -0
- praisonai/cli/features/ollama.py +361 -0
- praisonai/cli/features/output_style.py +273 -0
- praisonai/cli/features/package.py +631 -0
- praisonai/cli/features/performance.py +308 -0
- praisonai/cli/features/persistence.py +636 -0
- praisonai/cli/features/profile.py +226 -0
- praisonai/cli/features/profiler/__init__.py +81 -0
- praisonai/cli/features/profiler/core.py +558 -0
- praisonai/cli/features/profiler/optimizations.py +652 -0
- praisonai/cli/features/profiler/suite.py +386 -0
- praisonai/cli/features/profiling.py +350 -0
- praisonai/cli/features/queue/__init__.py +73 -0
- praisonai/cli/features/queue/manager.py +395 -0
- praisonai/cli/features/queue/models.py +286 -0
- praisonai/cli/features/queue/persistence.py +564 -0
- praisonai/cli/features/queue/scheduler.py +484 -0
- praisonai/cli/features/queue/worker.py +372 -0
- praisonai/cli/features/recipe.py +1723 -0
- praisonai/cli/features/recipes.py +449 -0
- praisonai/cli/features/registry.py +229 -0
- praisonai/cli/features/repo_map.py +860 -0
- praisonai/cli/features/router.py +466 -0
- praisonai/cli/features/sandbox_executor.py +515 -0
- praisonai/cli/features/serve.py +829 -0
- praisonai/cli/features/session.py +222 -0
- praisonai/cli/features/skills.py +856 -0
- praisonai/cli/features/slash_commands.py +650 -0
- praisonai/cli/features/telemetry.py +179 -0
- praisonai/cli/features/templates.py +1384 -0
- praisonai/cli/features/thinking.py +305 -0
- praisonai/cli/features/todo.py +334 -0
- praisonai/cli/features/tools.py +680 -0
- praisonai/cli/features/tui/__init__.py +83 -0
- praisonai/cli/features/tui/app.py +580 -0
- praisonai/cli/features/tui/cli.py +566 -0
- praisonai/cli/features/tui/debug.py +511 -0
- praisonai/cli/features/tui/events.py +99 -0
- praisonai/cli/features/tui/mock_provider.py +328 -0
- praisonai/cli/features/tui/orchestrator.py +652 -0
- praisonai/cli/features/tui/screens/__init__.py +50 -0
- praisonai/cli/features/tui/screens/main.py +245 -0
- praisonai/cli/features/tui/screens/queue.py +174 -0
- praisonai/cli/features/tui/screens/session.py +124 -0
- praisonai/cli/features/tui/screens/settings.py +148 -0
- praisonai/cli/features/tui/widgets/__init__.py +56 -0
- praisonai/cli/features/tui/widgets/chat.py +261 -0
- praisonai/cli/features/tui/widgets/composer.py +224 -0
- praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
- praisonai/cli/features/tui/widgets/status.py +167 -0
- praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
- praisonai/cli/features/workflow.py +720 -0
- praisonai/cli/legacy.py +236 -0
- praisonai/cli/main.py +5559 -0
- praisonai/cli/schedule_cli.py +54 -0
- praisonai/cli/state/__init__.py +31 -0
- praisonai/cli/state/identifiers.py +161 -0
- praisonai/cli/state/sessions.py +313 -0
- praisonai/code/__init__.py +93 -0
- praisonai/code/agent_tools.py +344 -0
- praisonai/code/diff/__init__.py +21 -0
- praisonai/code/diff/diff_strategy.py +432 -0
- praisonai/code/tools/__init__.py +27 -0
- praisonai/code/tools/apply_diff.py +221 -0
- praisonai/code/tools/execute_command.py +275 -0
- praisonai/code/tools/list_files.py +274 -0
- praisonai/code/tools/read_file.py +206 -0
- praisonai/code/tools/search_replace.py +248 -0
- praisonai/code/tools/write_file.py +217 -0
- praisonai/code/utils/__init__.py +46 -0
- praisonai/code/utils/file_utils.py +307 -0
- praisonai/code/utils/ignore_utils.py +308 -0
- praisonai/code/utils/text_utils.py +276 -0
- praisonai/db/__init__.py +64 -0
- praisonai/db/adapter.py +531 -0
- praisonai/deploy/__init__.py +62 -0
- praisonai/deploy/api.py +231 -0
- praisonai/deploy/docker.py +454 -0
- praisonai/deploy/doctor.py +367 -0
- praisonai/deploy/main.py +327 -0
- praisonai/deploy/models.py +179 -0
- praisonai/deploy/providers/__init__.py +33 -0
- praisonai/deploy/providers/aws.py +331 -0
- praisonai/deploy/providers/azure.py +358 -0
- praisonai/deploy/providers/base.py +101 -0
- praisonai/deploy/providers/gcp.py +314 -0
- praisonai/deploy/schema.py +208 -0
- praisonai/deploy.py +185 -0
- praisonai/endpoints/__init__.py +53 -0
- praisonai/endpoints/a2u_server.py +410 -0
- praisonai/endpoints/discovery.py +165 -0
- praisonai/endpoints/providers/__init__.py +28 -0
- praisonai/endpoints/providers/a2a.py +253 -0
- praisonai/endpoints/providers/a2u.py +208 -0
- praisonai/endpoints/providers/agents_api.py +171 -0
- praisonai/endpoints/providers/base.py +231 -0
- praisonai/endpoints/providers/mcp.py +263 -0
- praisonai/endpoints/providers/recipe.py +206 -0
- praisonai/endpoints/providers/tools_mcp.py +150 -0
- praisonai/endpoints/registry.py +131 -0
- praisonai/endpoints/server.py +161 -0
- praisonai/inbuilt_tools/__init__.py +24 -0
- praisonai/inbuilt_tools/autogen_tools.py +117 -0
- praisonai/inc/__init__.py +2 -0
- praisonai/inc/config.py +96 -0
- praisonai/inc/models.py +155 -0
- praisonai/integrations/__init__.py +56 -0
- praisonai/integrations/base.py +303 -0
- praisonai/integrations/claude_code.py +270 -0
- praisonai/integrations/codex_cli.py +255 -0
- praisonai/integrations/cursor_cli.py +195 -0
- praisonai/integrations/gemini_cli.py +222 -0
- praisonai/jobs/__init__.py +67 -0
- praisonai/jobs/executor.py +425 -0
- praisonai/jobs/models.py +230 -0
- praisonai/jobs/router.py +314 -0
- praisonai/jobs/server.py +186 -0
- praisonai/jobs/store.py +203 -0
- praisonai/llm/__init__.py +66 -0
- praisonai/llm/registry.py +382 -0
- praisonai/mcp_server/__init__.py +152 -0
- praisonai/mcp_server/adapters/__init__.py +74 -0
- praisonai/mcp_server/adapters/agents.py +128 -0
- praisonai/mcp_server/adapters/capabilities.py +168 -0
- praisonai/mcp_server/adapters/cli_tools.py +568 -0
- praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
- praisonai/mcp_server/adapters/knowledge.py +93 -0
- praisonai/mcp_server/adapters/memory.py +104 -0
- praisonai/mcp_server/adapters/prompts.py +306 -0
- praisonai/mcp_server/adapters/resources.py +124 -0
- praisonai/mcp_server/adapters/tools_bridge.py +280 -0
- praisonai/mcp_server/auth/__init__.py +48 -0
- praisonai/mcp_server/auth/api_key.py +291 -0
- praisonai/mcp_server/auth/oauth.py +460 -0
- praisonai/mcp_server/auth/oidc.py +289 -0
- praisonai/mcp_server/auth/scopes.py +260 -0
- praisonai/mcp_server/cli.py +852 -0
- praisonai/mcp_server/elicitation.py +445 -0
- praisonai/mcp_server/icons.py +302 -0
- praisonai/mcp_server/recipe_adapter.py +573 -0
- praisonai/mcp_server/recipe_cli.py +824 -0
- praisonai/mcp_server/registry.py +703 -0
- praisonai/mcp_server/sampling.py +422 -0
- praisonai/mcp_server/server.py +490 -0
- praisonai/mcp_server/tasks.py +443 -0
- praisonai/mcp_server/transports/__init__.py +18 -0
- praisonai/mcp_server/transports/http_stream.py +376 -0
- praisonai/mcp_server/transports/stdio.py +132 -0
- praisonai/persistence/__init__.py +84 -0
- praisonai/persistence/config.py +238 -0
- praisonai/persistence/conversation/__init__.py +25 -0
- praisonai/persistence/conversation/async_mysql.py +427 -0
- praisonai/persistence/conversation/async_postgres.py +410 -0
- praisonai/persistence/conversation/async_sqlite.py +371 -0
- praisonai/persistence/conversation/base.py +151 -0
- praisonai/persistence/conversation/json_store.py +250 -0
- praisonai/persistence/conversation/mysql.py +387 -0
- praisonai/persistence/conversation/postgres.py +401 -0
- praisonai/persistence/conversation/singlestore.py +240 -0
- praisonai/persistence/conversation/sqlite.py +341 -0
- praisonai/persistence/conversation/supabase.py +203 -0
- praisonai/persistence/conversation/surrealdb.py +287 -0
- praisonai/persistence/factory.py +301 -0
- praisonai/persistence/hooks/__init__.py +18 -0
- praisonai/persistence/hooks/agent_hooks.py +297 -0
- praisonai/persistence/knowledge/__init__.py +26 -0
- praisonai/persistence/knowledge/base.py +144 -0
- praisonai/persistence/knowledge/cassandra.py +232 -0
- praisonai/persistence/knowledge/chroma.py +295 -0
- praisonai/persistence/knowledge/clickhouse.py +242 -0
- praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
- praisonai/persistence/knowledge/couchbase.py +286 -0
- praisonai/persistence/knowledge/lancedb.py +216 -0
- praisonai/persistence/knowledge/langchain_adapter.py +291 -0
- praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
- praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
- praisonai/persistence/knowledge/milvus.py +277 -0
- praisonai/persistence/knowledge/mongodb_vector.py +306 -0
- praisonai/persistence/knowledge/pgvector.py +335 -0
- praisonai/persistence/knowledge/pinecone.py +253 -0
- praisonai/persistence/knowledge/qdrant.py +301 -0
- praisonai/persistence/knowledge/redis_vector.py +291 -0
- praisonai/persistence/knowledge/singlestore_vector.py +299 -0
- praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
- praisonai/persistence/knowledge/upstash_vector.py +266 -0
- praisonai/persistence/knowledge/weaviate.py +223 -0
- praisonai/persistence/migrations/__init__.py +10 -0
- praisonai/persistence/migrations/manager.py +251 -0
- praisonai/persistence/orchestrator.py +406 -0
- praisonai/persistence/state/__init__.py +21 -0
- praisonai/persistence/state/async_mongodb.py +200 -0
- praisonai/persistence/state/base.py +107 -0
- praisonai/persistence/state/dynamodb.py +226 -0
- praisonai/persistence/state/firestore.py +175 -0
- praisonai/persistence/state/gcs.py +155 -0
- praisonai/persistence/state/memory.py +245 -0
- praisonai/persistence/state/mongodb.py +158 -0
- praisonai/persistence/state/redis.py +190 -0
- praisonai/persistence/state/upstash.py +144 -0
- praisonai/persistence/tests/__init__.py +3 -0
- praisonai/persistence/tests/test_all_backends.py +633 -0
- praisonai/profiler.py +1214 -0
- praisonai/recipe/__init__.py +134 -0
- praisonai/recipe/bridge.py +278 -0
- praisonai/recipe/core.py +893 -0
- praisonai/recipe/exceptions.py +54 -0
- praisonai/recipe/history.py +402 -0
- praisonai/recipe/models.py +266 -0
- praisonai/recipe/operations.py +440 -0
- praisonai/recipe/policy.py +422 -0
- praisonai/recipe/registry.py +849 -0
- praisonai/recipe/runtime.py +214 -0
- praisonai/recipe/security.py +711 -0
- praisonai/recipe/serve.py +859 -0
- praisonai/recipe/server.py +613 -0
- praisonai/scheduler/__init__.py +45 -0
- praisonai/scheduler/agent_scheduler.py +552 -0
- praisonai/scheduler/base.py +124 -0
- praisonai/scheduler/daemon_manager.py +225 -0
- praisonai/scheduler/state_manager.py +155 -0
- praisonai/scheduler/yaml_loader.py +193 -0
- praisonai/scheduler.py +194 -0
- praisonai/setup/__init__.py +1 -0
- praisonai/setup/build.py +21 -0
- praisonai/setup/post_install.py +23 -0
- praisonai/setup/setup_conda_env.py +25 -0
- praisonai/setup.py +16 -0
- praisonai/templates/__init__.py +116 -0
- praisonai/templates/cache.py +364 -0
- praisonai/templates/dependency_checker.py +358 -0
- praisonai/templates/discovery.py +391 -0
- praisonai/templates/loader.py +564 -0
- praisonai/templates/registry.py +511 -0
- praisonai/templates/resolver.py +206 -0
- praisonai/templates/security.py +327 -0
- praisonai/templates/tool_override.py +498 -0
- praisonai/templates/tools_doctor.py +256 -0
- praisonai/test.py +105 -0
- praisonai/train.py +562 -0
- praisonai/train_vision.py +306 -0
- praisonai/ui/agents.py +824 -0
- praisonai/ui/callbacks.py +57 -0
- praisonai/ui/chainlit_compat.py +246 -0
- praisonai/ui/chat.py +532 -0
- praisonai/ui/code.py +717 -0
- praisonai/ui/colab.py +474 -0
- praisonai/ui/colab_chainlit.py +81 -0
- praisonai/ui/components/aicoder.py +284 -0
- praisonai/ui/context.py +283 -0
- praisonai/ui/database_config.py +56 -0
- praisonai/ui/db.py +294 -0
- praisonai/ui/realtime.py +488 -0
- praisonai/ui/realtimeclient/__init__.py +756 -0
- praisonai/ui/realtimeclient/tools.py +242 -0
- praisonai/ui/sql_alchemy.py +710 -0
- praisonai/upload_vision.py +140 -0
- praisonai/version.py +1 -0
- praisonai-3.0.0.dist-info/METADATA +3493 -0
- praisonai-3.0.0.dist-info/RECORD +393 -0
- praisonai-3.0.0.dist-info/WHEEL +5 -0
- praisonai-3.0.0.dist-info/entry_points.txt +4 -0
- praisonai-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,852 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MCP Server CLI Integration
|
|
3
|
+
|
|
4
|
+
Provides CLI commands for managing the MCP server:
|
|
5
|
+
- praisonai mcp serve --transport stdio|http-stream
|
|
6
|
+
- praisonai mcp list-tools
|
|
7
|
+
- praisonai mcp config-generate
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import json
|
|
12
|
+
import logging
|
|
13
|
+
import sys
|
|
14
|
+
from typing import List
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class MCPServerCLI:
|
|
20
|
+
"""CLI handler for MCP server commands."""
|
|
21
|
+
|
|
22
|
+
EXIT_SUCCESS = 0
|
|
23
|
+
EXIT_ERROR = 1
|
|
24
|
+
|
|
25
|
+
def __init__(self):
|
|
26
|
+
"""Initialize CLI handler."""
|
|
27
|
+
self._server = None
|
|
28
|
+
|
|
29
|
+
def handle(self, args: List[str]) -> int:
|
|
30
|
+
"""
|
|
31
|
+
Handle MCP CLI subcommand.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
args: Command arguments
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Exit code
|
|
38
|
+
"""
|
|
39
|
+
if not args:
|
|
40
|
+
self._print_help()
|
|
41
|
+
return self.EXIT_SUCCESS
|
|
42
|
+
|
|
43
|
+
command = args[0]
|
|
44
|
+
remaining = args[1:]
|
|
45
|
+
|
|
46
|
+
commands = {
|
|
47
|
+
"serve": self.cmd_serve,
|
|
48
|
+
"serve-recipe": self.cmd_serve_recipe,
|
|
49
|
+
"list-tools": self.cmd_list_tools,
|
|
50
|
+
"list-resources": self.cmd_list_resources,
|
|
51
|
+
"list-prompts": self.cmd_list_prompts,
|
|
52
|
+
"list-recipes": self.cmd_list_recipes,
|
|
53
|
+
"tools": self.cmd_tools, # New: tools subcommand
|
|
54
|
+
"validate-recipe": self.cmd_validate_recipe,
|
|
55
|
+
"inspect-recipe": self.cmd_inspect_recipe,
|
|
56
|
+
"config-generate": self.cmd_config_generate,
|
|
57
|
+
"config-generate-recipe": self.cmd_config_generate_recipe,
|
|
58
|
+
"auth": self.cmd_auth,
|
|
59
|
+
"tasks": self.cmd_tasks,
|
|
60
|
+
"doctor": self.cmd_doctor,
|
|
61
|
+
"help": lambda _: self._print_help() or self.EXIT_SUCCESS,
|
|
62
|
+
"--help": lambda _: self._print_help() or self.EXIT_SUCCESS,
|
|
63
|
+
"-h": lambda _: self._print_help() or self.EXIT_SUCCESS,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if command in commands:
|
|
67
|
+
return commands[command](remaining)
|
|
68
|
+
else:
|
|
69
|
+
self._print_error(f"Unknown command: {command}")
|
|
70
|
+
self._print_help()
|
|
71
|
+
return self.EXIT_ERROR
|
|
72
|
+
|
|
73
|
+
def _print_help(self) -> None:
|
|
74
|
+
"""Print help message."""
|
|
75
|
+
help_text = """
|
|
76
|
+
[bold cyan]PraisonAI MCP Server (Protocol Version 2025-11-25)[/bold cyan]
|
|
77
|
+
|
|
78
|
+
Run PraisonAI as an MCP server for Claude Desktop, Cursor, Windsurf, and other MCP clients.
|
|
79
|
+
|
|
80
|
+
[bold]Usage:[/bold]
|
|
81
|
+
praisonai mcp <command> [options]
|
|
82
|
+
|
|
83
|
+
[bold]Commands:[/bold]
|
|
84
|
+
serve Start the MCP server
|
|
85
|
+
serve-recipe Serve a recipe as MCP server
|
|
86
|
+
list-tools List available MCP tools
|
|
87
|
+
list-resources List available MCP resources
|
|
88
|
+
list-prompts List available MCP prompts
|
|
89
|
+
list-recipes List available recipes
|
|
90
|
+
tools Tool management commands (search, info, schema)
|
|
91
|
+
validate-recipe Validate recipe MCP compatibility
|
|
92
|
+
inspect-recipe Inspect recipe MCP schema
|
|
93
|
+
config-generate Generate client configuration
|
|
94
|
+
config-generate-recipe Generate config for recipe server
|
|
95
|
+
auth Authentication commands
|
|
96
|
+
tasks Tasks API commands
|
|
97
|
+
doctor Check MCP server health
|
|
98
|
+
|
|
99
|
+
[bold]Serve Options:[/bold]
|
|
100
|
+
--transport <type> Transport: stdio (default) or http-stream
|
|
101
|
+
--host <host> HTTP host (default: 127.0.0.1)
|
|
102
|
+
--port <port> HTTP port (default: 8080)
|
|
103
|
+
--endpoint <path> HTTP endpoint (default: /mcp)
|
|
104
|
+
--api-key <key> API key for authentication
|
|
105
|
+
--name <name> Server name (default: praisonai)
|
|
106
|
+
--response-mode <mode> Response mode: batch (default) or stream
|
|
107
|
+
--cors-origins <list> Comma-separated CORS origins
|
|
108
|
+
--allowed-origins <list> Comma-separated allowed origins for security
|
|
109
|
+
--session-ttl <secs> Session TTL in seconds (default: 3600)
|
|
110
|
+
--no-termination Disable client session termination
|
|
111
|
+
--resumability Enable SSE resumability (default: true)
|
|
112
|
+
--log-level <level> Log level: debug, info, warning, error
|
|
113
|
+
--json Output in JSON format
|
|
114
|
+
|
|
115
|
+
[bold]Config Generate Options:[/bold]
|
|
116
|
+
--client <name> Client type: claude-desktop, cursor, vscode, windsurf
|
|
117
|
+
--output <path> Output file path
|
|
118
|
+
--transport <type> Transport for config
|
|
119
|
+
|
|
120
|
+
[bold]Examples:[/bold]
|
|
121
|
+
# Start STDIO server (for Claude Desktop)
|
|
122
|
+
praisonai mcp serve --transport stdio
|
|
123
|
+
|
|
124
|
+
# Start HTTP Stream server with authentication
|
|
125
|
+
praisonai mcp serve --transport http-stream --port 8080 --api-key mykey
|
|
126
|
+
|
|
127
|
+
# Start with custom allowed origins
|
|
128
|
+
praisonai mcp serve --transport http-stream --allowed-origins "http://localhost:3000"
|
|
129
|
+
|
|
130
|
+
# Generate Claude Desktop config
|
|
131
|
+
praisonai mcp config-generate --client claude-desktop
|
|
132
|
+
|
|
133
|
+
# List available tools
|
|
134
|
+
praisonai mcp list-tools
|
|
135
|
+
|
|
136
|
+
# Check MCP server health
|
|
137
|
+
praisonai mcp doctor
|
|
138
|
+
|
|
139
|
+
[bold]Recipe Server Examples:[/bold]
|
|
140
|
+
# Serve a recipe as STDIO MCP server
|
|
141
|
+
praisonai mcp serve-recipe support-reply --transport stdio
|
|
142
|
+
|
|
143
|
+
# Serve with HTTP Stream transport
|
|
144
|
+
praisonai mcp serve-recipe ai-video-editor --transport http-stream --port 8080
|
|
145
|
+
|
|
146
|
+
# Generate config for recipe server
|
|
147
|
+
praisonai mcp config-generate-recipe support-reply --client claude-desktop
|
|
148
|
+
"""
|
|
149
|
+
self._print_rich(help_text)
|
|
150
|
+
|
|
151
|
+
def _print_rich(self, text: str) -> None:
|
|
152
|
+
"""Print with rich formatting if available."""
|
|
153
|
+
try:
|
|
154
|
+
from rich import print as rprint
|
|
155
|
+
rprint(text)
|
|
156
|
+
except ImportError:
|
|
157
|
+
import re
|
|
158
|
+
plain = re.sub(r'\[/?[^\]]+\]', '', text)
|
|
159
|
+
print(plain)
|
|
160
|
+
|
|
161
|
+
def _print_error(self, message: str) -> None:
|
|
162
|
+
"""Print error message."""
|
|
163
|
+
try:
|
|
164
|
+
from rich import print as rprint
|
|
165
|
+
rprint(f"[red]Error: {message}[/red]")
|
|
166
|
+
except ImportError:
|
|
167
|
+
print(f"Error: {message}", file=sys.stderr)
|
|
168
|
+
|
|
169
|
+
def _print_success(self, message: str) -> None:
|
|
170
|
+
"""Print success message."""
|
|
171
|
+
try:
|
|
172
|
+
from rich import print as rprint
|
|
173
|
+
rprint(f"[green]✓ {message}[/green]")
|
|
174
|
+
except ImportError:
|
|
175
|
+
print(f"✓ {message}")
|
|
176
|
+
|
|
177
|
+
def cmd_serve(self, args: List[str]) -> int:
|
|
178
|
+
"""Start the MCP server."""
|
|
179
|
+
parser = argparse.ArgumentParser(prog="praisonai mcp serve")
|
|
180
|
+
parser.add_argument("--transport", default="stdio", choices=["stdio", "http-stream"])
|
|
181
|
+
parser.add_argument("--host", default="127.0.0.1")
|
|
182
|
+
parser.add_argument("--port", type=int, default=8080)
|
|
183
|
+
parser.add_argument("--endpoint", default="/mcp")
|
|
184
|
+
parser.add_argument("--api-key", default=None)
|
|
185
|
+
parser.add_argument("--name", default="praisonai")
|
|
186
|
+
parser.add_argument("--debug", action="store_true")
|
|
187
|
+
parser.add_argument("--response-mode", default="batch", choices=["batch", "stream"])
|
|
188
|
+
parser.add_argument("--cors-origins", default=None, help="Comma-separated CORS origins")
|
|
189
|
+
parser.add_argument("--allowed-origins", default=None, help="Comma-separated allowed origins for security")
|
|
190
|
+
parser.add_argument("--session-ttl", type=int, default=3600, help="Session TTL in seconds")
|
|
191
|
+
parser.add_argument("--allow-termination", action="store_true", default=True, help="Allow client session termination")
|
|
192
|
+
parser.add_argument("--no-termination", action="store_true", help="Disable client session termination")
|
|
193
|
+
parser.add_argument("--resumability", action="store_true", default=True, help="Enable SSE resumability")
|
|
194
|
+
parser.add_argument("--log-level", default="warning", choices=["debug", "info", "warning", "error"])
|
|
195
|
+
parser.add_argument("--json", action="store_true", help="Output in JSON format")
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
parsed = parser.parse_args(args)
|
|
199
|
+
except SystemExit:
|
|
200
|
+
return self.EXIT_ERROR
|
|
201
|
+
|
|
202
|
+
# Configure logging
|
|
203
|
+
log_levels = {
|
|
204
|
+
"debug": logging.DEBUG,
|
|
205
|
+
"info": logging.INFO,
|
|
206
|
+
"warning": logging.WARNING,
|
|
207
|
+
"error": logging.ERROR,
|
|
208
|
+
}
|
|
209
|
+
log_level = log_levels.get(parsed.log_level, logging.WARNING)
|
|
210
|
+
if parsed.debug:
|
|
211
|
+
log_level = logging.DEBUG
|
|
212
|
+
logging.basicConfig(level=log_level, stream=sys.stderr)
|
|
213
|
+
|
|
214
|
+
try:
|
|
215
|
+
from .server import MCPServer
|
|
216
|
+
from .adapters import register_all
|
|
217
|
+
|
|
218
|
+
# Register all tools, resources, and prompts
|
|
219
|
+
register_all()
|
|
220
|
+
|
|
221
|
+
# Create server
|
|
222
|
+
server = MCPServer(
|
|
223
|
+
name=parsed.name,
|
|
224
|
+
instructions="PraisonAI MCP Server - AI agent capabilities exposed via MCP protocol.",
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
if parsed.transport == "stdio":
|
|
228
|
+
# STDIO mode - minimal output to stderr
|
|
229
|
+
logger.info(f"Starting MCP server '{parsed.name}' on STDIO transport")
|
|
230
|
+
server.run_stdio()
|
|
231
|
+
else:
|
|
232
|
+
# HTTP Stream mode
|
|
233
|
+
cors_origins = parsed.cors_origins.split(",") if parsed.cors_origins else None
|
|
234
|
+
allowed_origins = parsed.allowed_origins.split(",") if parsed.allowed_origins else None
|
|
235
|
+
allow_termination = not parsed.no_termination
|
|
236
|
+
|
|
237
|
+
if not parsed.json:
|
|
238
|
+
self._print_success(f"Starting MCP server '{parsed.name}' on http://{parsed.host}:{parsed.port}{parsed.endpoint}")
|
|
239
|
+
|
|
240
|
+
server.run_http_stream(
|
|
241
|
+
host=parsed.host,
|
|
242
|
+
port=parsed.port,
|
|
243
|
+
endpoint=parsed.endpoint,
|
|
244
|
+
api_key=parsed.api_key,
|
|
245
|
+
cors_origins=cors_origins,
|
|
246
|
+
allowed_origins=allowed_origins,
|
|
247
|
+
session_ttl=parsed.session_ttl,
|
|
248
|
+
allow_client_termination=allow_termination,
|
|
249
|
+
response_mode=parsed.response_mode,
|
|
250
|
+
resumability_enabled=parsed.resumability,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
return self.EXIT_SUCCESS
|
|
254
|
+
|
|
255
|
+
except ImportError as e:
|
|
256
|
+
self._print_error(f"Missing dependency: {e}")
|
|
257
|
+
print("Install with: pip install praisonai[mcp]", file=sys.stderr)
|
|
258
|
+
return self.EXIT_ERROR
|
|
259
|
+
except KeyboardInterrupt:
|
|
260
|
+
logger.info("Server stopped by user")
|
|
261
|
+
return self.EXIT_SUCCESS
|
|
262
|
+
except Exception as e:
|
|
263
|
+
self._print_error(str(e))
|
|
264
|
+
return self.EXIT_ERROR
|
|
265
|
+
|
|
266
|
+
def cmd_list_tools(self, args: List[str]) -> int:
|
|
267
|
+
"""List available MCP tools."""
|
|
268
|
+
parser = argparse.ArgumentParser(prog="praisonai mcp list-tools")
|
|
269
|
+
parser.add_argument("--json", action="store_true", help="Output in JSON format")
|
|
270
|
+
parser.add_argument("--cursor", default=None, help="Pagination cursor")
|
|
271
|
+
parser.add_argument("--limit", type=int, default=50, help="Max tools to show")
|
|
272
|
+
|
|
273
|
+
try:
|
|
274
|
+
parsed = parser.parse_args(args)
|
|
275
|
+
except SystemExit:
|
|
276
|
+
return self.EXIT_ERROR
|
|
277
|
+
|
|
278
|
+
try:
|
|
279
|
+
from .adapters import register_all_tools
|
|
280
|
+
from .registry import get_tool_registry
|
|
281
|
+
|
|
282
|
+
# Register all tools
|
|
283
|
+
register_all_tools()
|
|
284
|
+
|
|
285
|
+
registry = get_tool_registry()
|
|
286
|
+
tools, next_cursor = registry.list_paginated(
|
|
287
|
+
cursor=parsed.cursor,
|
|
288
|
+
page_size=parsed.limit
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
if parsed.json:
|
|
292
|
+
result = {"tools": tools}
|
|
293
|
+
if next_cursor:
|
|
294
|
+
result["nextCursor"] = next_cursor
|
|
295
|
+
print(json.dumps(result, indent=2))
|
|
296
|
+
return self.EXIT_SUCCESS
|
|
297
|
+
|
|
298
|
+
if not tools:
|
|
299
|
+
print("No tools registered")
|
|
300
|
+
return self.EXIT_SUCCESS
|
|
301
|
+
|
|
302
|
+
total = len(registry.list_all())
|
|
303
|
+
self._print_rich(f"\n[bold]Available MCP Tools ({len(tools)} of {total}):[/bold]\n")
|
|
304
|
+
for tool in tools:
|
|
305
|
+
name = tool.get("name", "unknown")
|
|
306
|
+
desc = tool.get("description", "No description")
|
|
307
|
+
annotations = tool.get("annotations", {})
|
|
308
|
+
hints = []
|
|
309
|
+
if annotations.get("readOnlyHint"):
|
|
310
|
+
hints.append("read-only")
|
|
311
|
+
if annotations.get("destructiveHint"):
|
|
312
|
+
hints.append("destructive")
|
|
313
|
+
hint_str = f" [{', '.join(hints)}]" if hints else ""
|
|
314
|
+
print(f" • {name}{hint_str}")
|
|
315
|
+
print(f" {desc}\n")
|
|
316
|
+
|
|
317
|
+
if next_cursor:
|
|
318
|
+
print(f"[dim]More results available. Use --cursor {next_cursor}[/dim]\n")
|
|
319
|
+
|
|
320
|
+
return self.EXIT_SUCCESS
|
|
321
|
+
|
|
322
|
+
except Exception as e:
|
|
323
|
+
self._print_error(str(e))
|
|
324
|
+
return self.EXIT_ERROR
|
|
325
|
+
|
|
326
|
+
def cmd_tools(self, args: List[str]) -> int:
|
|
327
|
+
"""Handle tools subcommands: search, info, schema."""
|
|
328
|
+
if not args:
|
|
329
|
+
self._print_tools_help()
|
|
330
|
+
return self.EXIT_SUCCESS
|
|
331
|
+
|
|
332
|
+
subcommand = args[0]
|
|
333
|
+
remaining = args[1:]
|
|
334
|
+
|
|
335
|
+
subcommands = {
|
|
336
|
+
"search": self.cmd_tools_search,
|
|
337
|
+
"info": self.cmd_tools_info,
|
|
338
|
+
"schema": self.cmd_tools_schema,
|
|
339
|
+
"list": lambda a: self.cmd_list_tools(a),
|
|
340
|
+
"help": lambda _: self._print_tools_help() or self.EXIT_SUCCESS,
|
|
341
|
+
"--help": lambda _: self._print_tools_help() or self.EXIT_SUCCESS,
|
|
342
|
+
"-h": lambda _: self._print_tools_help() or self.EXIT_SUCCESS,
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if subcommand in subcommands:
|
|
346
|
+
return subcommands[subcommand](remaining)
|
|
347
|
+
else:
|
|
348
|
+
self._print_error(f"Unknown tools subcommand: {subcommand}")
|
|
349
|
+
self._print_tools_help()
|
|
350
|
+
return self.EXIT_ERROR
|
|
351
|
+
|
|
352
|
+
def _print_tools_help(self) -> None:
|
|
353
|
+
"""Print tools subcommand help."""
|
|
354
|
+
help_text = """
|
|
355
|
+
[bold cyan]PraisonAI MCP Tools Management[/bold cyan]
|
|
356
|
+
|
|
357
|
+
[bold]Usage:[/bold]
|
|
358
|
+
praisonai mcp tools <subcommand> [options]
|
|
359
|
+
|
|
360
|
+
[bold]Subcommands:[/bold]
|
|
361
|
+
search Search tools by query, category, or tags
|
|
362
|
+
info Get detailed information about a tool
|
|
363
|
+
schema Get the JSON schema for a tool
|
|
364
|
+
list List all tools (alias for list-tools)
|
|
365
|
+
|
|
366
|
+
[bold]Search Options:[/bold]
|
|
367
|
+
praisonai mcp tools search "<query>" [options]
|
|
368
|
+
--category <cat> Filter by category
|
|
369
|
+
--tag <tag> Filter by tag (can repeat)
|
|
370
|
+
--read-only Show only read-only tools
|
|
371
|
+
--json Output in JSON format
|
|
372
|
+
--limit <n> Max results (default: 50)
|
|
373
|
+
--cursor <cursor> Pagination cursor
|
|
374
|
+
|
|
375
|
+
[bold]Info Options:[/bold]
|
|
376
|
+
praisonai mcp tools info <tool-name>
|
|
377
|
+
--json Output in JSON format
|
|
378
|
+
|
|
379
|
+
[bold]Schema Options:[/bold]
|
|
380
|
+
praisonai mcp tools schema <tool-name>
|
|
381
|
+
--json Output in JSON format (default)
|
|
382
|
+
|
|
383
|
+
[bold]Examples:[/bold]
|
|
384
|
+
# Search for web-related tools
|
|
385
|
+
praisonai mcp tools search "web"
|
|
386
|
+
|
|
387
|
+
# Search read-only tools in memory category
|
|
388
|
+
praisonai mcp tools search --category memory --read-only
|
|
389
|
+
|
|
390
|
+
# Get tool info
|
|
391
|
+
praisonai mcp tools info praisonai.memory.show
|
|
392
|
+
|
|
393
|
+
# Get tool schema
|
|
394
|
+
praisonai mcp tools schema praisonai.workflow.run
|
|
395
|
+
"""
|
|
396
|
+
self._print_rich(help_text)
|
|
397
|
+
|
|
398
|
+
def cmd_tools_search(self, args: List[str]) -> int:
|
|
399
|
+
"""Search tools by query, category, or tags."""
|
|
400
|
+
parser = argparse.ArgumentParser(prog="praisonai mcp tools search")
|
|
401
|
+
parser.add_argument("query", nargs="?", default=None, help="Search query")
|
|
402
|
+
parser.add_argument("--category", default=None, help="Filter by category")
|
|
403
|
+
parser.add_argument("--tag", action="append", dest="tags", help="Filter by tag")
|
|
404
|
+
parser.add_argument("--read-only", action="store_true", help="Show only read-only tools")
|
|
405
|
+
parser.add_argument("--json", action="store_true", help="Output in JSON format")
|
|
406
|
+
parser.add_argument("--limit", type=int, default=50, help="Max results")
|
|
407
|
+
parser.add_argument("--cursor", default=None, help="Pagination cursor")
|
|
408
|
+
|
|
409
|
+
try:
|
|
410
|
+
parsed = parser.parse_args(args)
|
|
411
|
+
except SystemExit:
|
|
412
|
+
return self.EXIT_ERROR
|
|
413
|
+
|
|
414
|
+
try:
|
|
415
|
+
from .adapters import register_all_tools
|
|
416
|
+
from .registry import get_tool_registry
|
|
417
|
+
|
|
418
|
+
register_all_tools()
|
|
419
|
+
registry = get_tool_registry()
|
|
420
|
+
|
|
421
|
+
read_only = True if parsed.read_only else None
|
|
422
|
+
|
|
423
|
+
tools, next_cursor, total = registry.search(
|
|
424
|
+
query=parsed.query,
|
|
425
|
+
category=parsed.category,
|
|
426
|
+
tags=parsed.tags,
|
|
427
|
+
read_only=read_only,
|
|
428
|
+
cursor=parsed.cursor,
|
|
429
|
+
page_size=parsed.limit,
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
if parsed.json:
|
|
433
|
+
result = {"tools": tools, "total": total}
|
|
434
|
+
if next_cursor:
|
|
435
|
+
result["nextCursor"] = next_cursor
|
|
436
|
+
print(json.dumps(result, indent=2))
|
|
437
|
+
return self.EXIT_SUCCESS
|
|
438
|
+
|
|
439
|
+
if not tools:
|
|
440
|
+
print("No tools found matching your criteria")
|
|
441
|
+
return self.EXIT_SUCCESS
|
|
442
|
+
|
|
443
|
+
self._print_rich(f"\n[bold]Search Results ({len(tools)} of {total}):[/bold]\n")
|
|
444
|
+
for tool in tools:
|
|
445
|
+
name = tool.get("name", "unknown")
|
|
446
|
+
desc = tool.get("description", "No description")
|
|
447
|
+
annotations = tool.get("annotations", {})
|
|
448
|
+
hints = []
|
|
449
|
+
if annotations.get("readOnlyHint"):
|
|
450
|
+
hints.append("read-only")
|
|
451
|
+
if annotations.get("destructiveHint"):
|
|
452
|
+
hints.append("destructive")
|
|
453
|
+
hint_str = f" [{', '.join(hints)}]" if hints else ""
|
|
454
|
+
print(f" • {name}{hint_str}")
|
|
455
|
+
print(f" {desc}\n")
|
|
456
|
+
|
|
457
|
+
if next_cursor:
|
|
458
|
+
print(f"[dim]More results available. Use --cursor {next_cursor}[/dim]\n")
|
|
459
|
+
|
|
460
|
+
return self.EXIT_SUCCESS
|
|
461
|
+
|
|
462
|
+
except Exception as e:
|
|
463
|
+
self._print_error(str(e))
|
|
464
|
+
return self.EXIT_ERROR
|
|
465
|
+
|
|
466
|
+
def cmd_tools_info(self, args: List[str]) -> int:
|
|
467
|
+
"""Get detailed information about a tool."""
|
|
468
|
+
parser = argparse.ArgumentParser(prog="praisonai mcp tools info")
|
|
469
|
+
parser.add_argument("name", help="Tool name")
|
|
470
|
+
parser.add_argument("--json", action="store_true", help="Output in JSON format")
|
|
471
|
+
|
|
472
|
+
try:
|
|
473
|
+
parsed = parser.parse_args(args)
|
|
474
|
+
except SystemExit:
|
|
475
|
+
return self.EXIT_ERROR
|
|
476
|
+
|
|
477
|
+
try:
|
|
478
|
+
from .adapters import register_all_tools
|
|
479
|
+
from .registry import get_tool_registry
|
|
480
|
+
|
|
481
|
+
register_all_tools()
|
|
482
|
+
registry = get_tool_registry()
|
|
483
|
+
|
|
484
|
+
tool = registry.get(parsed.name)
|
|
485
|
+
if tool is None:
|
|
486
|
+
self._print_error(f"Tool not found: {parsed.name}")
|
|
487
|
+
return self.EXIT_ERROR
|
|
488
|
+
|
|
489
|
+
schema = tool.to_mcp_schema()
|
|
490
|
+
|
|
491
|
+
if parsed.json:
|
|
492
|
+
print(json.dumps(schema, indent=2))
|
|
493
|
+
return self.EXIT_SUCCESS
|
|
494
|
+
|
|
495
|
+
self._print_rich(f"\n[bold cyan]Tool: {tool.name}[/bold cyan]\n")
|
|
496
|
+
print(f"[bold]Description:[/bold] {tool.description}")
|
|
497
|
+
|
|
498
|
+
annotations = schema.get("annotations", {})
|
|
499
|
+
print("\n[bold]Annotations:[/bold]")
|
|
500
|
+
print(f" • readOnlyHint: {annotations.get('readOnlyHint', False)}")
|
|
501
|
+
print(f" • destructiveHint: {annotations.get('destructiveHint', True)}")
|
|
502
|
+
print(f" • idempotentHint: {annotations.get('idempotentHint', False)}")
|
|
503
|
+
print(f" • openWorldHint: {annotations.get('openWorldHint', True)}")
|
|
504
|
+
|
|
505
|
+
if tool.category:
|
|
506
|
+
print(f" • category: {tool.category}")
|
|
507
|
+
if tool.tags:
|
|
508
|
+
print(f" • tags: {', '.join(tool.tags)}")
|
|
509
|
+
|
|
510
|
+
input_schema = schema.get("inputSchema", {})
|
|
511
|
+
props = input_schema.get("properties", {})
|
|
512
|
+
required = input_schema.get("required", []) or []
|
|
513
|
+
|
|
514
|
+
if props:
|
|
515
|
+
print("\n[bold]Parameters:[/bold]")
|
|
516
|
+
for param_name, param_info in props.items():
|
|
517
|
+
req = " (required)" if param_name in required else ""
|
|
518
|
+
ptype = param_info.get("type", "any")
|
|
519
|
+
pdesc = param_info.get("description", "")
|
|
520
|
+
print(f" • {param_name}: {ptype}{req}")
|
|
521
|
+
if pdesc:
|
|
522
|
+
print(f" {pdesc}")
|
|
523
|
+
|
|
524
|
+
print()
|
|
525
|
+
return self.EXIT_SUCCESS
|
|
526
|
+
|
|
527
|
+
except Exception as e:
|
|
528
|
+
self._print_error(str(e))
|
|
529
|
+
return self.EXIT_ERROR
|
|
530
|
+
|
|
531
|
+
def cmd_tools_schema(self, args: List[str]) -> int:
|
|
532
|
+
"""Get the JSON schema for a tool."""
|
|
533
|
+
parser = argparse.ArgumentParser(prog="praisonai mcp tools schema")
|
|
534
|
+
parser.add_argument("name", help="Tool name")
|
|
535
|
+
|
|
536
|
+
try:
|
|
537
|
+
parsed = parser.parse_args(args)
|
|
538
|
+
except SystemExit:
|
|
539
|
+
return self.EXIT_ERROR
|
|
540
|
+
|
|
541
|
+
try:
|
|
542
|
+
from .adapters import register_all_tools
|
|
543
|
+
from .registry import get_tool_registry
|
|
544
|
+
|
|
545
|
+
register_all_tools()
|
|
546
|
+
registry = get_tool_registry()
|
|
547
|
+
|
|
548
|
+
tool = registry.get(parsed.name)
|
|
549
|
+
if tool is None:
|
|
550
|
+
self._print_error(f"Tool not found: {parsed.name}")
|
|
551
|
+
return self.EXIT_ERROR
|
|
552
|
+
|
|
553
|
+
schema = tool.to_mcp_schema()
|
|
554
|
+
print(json.dumps(schema, indent=2))
|
|
555
|
+
return self.EXIT_SUCCESS
|
|
556
|
+
|
|
557
|
+
except Exception as e:
|
|
558
|
+
self._print_error(str(e))
|
|
559
|
+
return self.EXIT_ERROR
|
|
560
|
+
|
|
561
|
+
def cmd_list_resources(self, args: List[str]) -> int:
|
|
562
|
+
"""List available MCP resources."""
|
|
563
|
+
try:
|
|
564
|
+
from .registry import get_resource_registry
|
|
565
|
+
|
|
566
|
+
registry = get_resource_registry()
|
|
567
|
+
resources = registry.list_schemas()
|
|
568
|
+
|
|
569
|
+
if not resources:
|
|
570
|
+
print("No resources registered")
|
|
571
|
+
return self.EXIT_SUCCESS
|
|
572
|
+
|
|
573
|
+
print(f"\n[bold]Available MCP Resources ({len(resources)}):[/bold]\n")
|
|
574
|
+
for res in resources:
|
|
575
|
+
uri = res.get("uri", "unknown")
|
|
576
|
+
desc = res.get("description", "No description")
|
|
577
|
+
print(f" • {uri}")
|
|
578
|
+
print(f" {desc}\n")
|
|
579
|
+
|
|
580
|
+
return self.EXIT_SUCCESS
|
|
581
|
+
|
|
582
|
+
except Exception as e:
|
|
583
|
+
self._print_error(str(e))
|
|
584
|
+
return self.EXIT_ERROR
|
|
585
|
+
|
|
586
|
+
def cmd_list_prompts(self, args: List[str]) -> int:
|
|
587
|
+
"""List available MCP prompts."""
|
|
588
|
+
try:
|
|
589
|
+
from .registry import get_prompt_registry
|
|
590
|
+
|
|
591
|
+
registry = get_prompt_registry()
|
|
592
|
+
prompts = registry.list_schemas()
|
|
593
|
+
|
|
594
|
+
if not prompts:
|
|
595
|
+
print("No prompts registered")
|
|
596
|
+
return self.EXIT_SUCCESS
|
|
597
|
+
|
|
598
|
+
print(f"\n[bold]Available MCP Prompts ({len(prompts)}):[/bold]\n")
|
|
599
|
+
for prompt in prompts:
|
|
600
|
+
name = prompt.get("name", "unknown")
|
|
601
|
+
desc = prompt.get("description", "No description")
|
|
602
|
+
print(f" • {name}")
|
|
603
|
+
print(f" {desc}\n")
|
|
604
|
+
|
|
605
|
+
return self.EXIT_SUCCESS
|
|
606
|
+
|
|
607
|
+
except Exception as e:
|
|
608
|
+
self._print_error(str(e))
|
|
609
|
+
return self.EXIT_ERROR
|
|
610
|
+
|
|
611
|
+
def cmd_config_generate(self, args: List[str]) -> int:
|
|
612
|
+
"""Generate client configuration."""
|
|
613
|
+
parser = argparse.ArgumentParser(prog="praisonai mcp config-generate")
|
|
614
|
+
parser.add_argument("--client", default="claude-desktop",
|
|
615
|
+
choices=["claude-desktop", "cursor", "vscode", "windsurf"])
|
|
616
|
+
parser.add_argument("--output", default=None)
|
|
617
|
+
parser.add_argument("--transport", default="stdio", choices=["stdio", "http-stream"])
|
|
618
|
+
parser.add_argument("--host", default="127.0.0.1")
|
|
619
|
+
parser.add_argument("--port", type=int, default=8080)
|
|
620
|
+
|
|
621
|
+
try:
|
|
622
|
+
parsed = parser.parse_args(args)
|
|
623
|
+
except SystemExit:
|
|
624
|
+
return self.EXIT_ERROR
|
|
625
|
+
|
|
626
|
+
# Generate config based on client type
|
|
627
|
+
if parsed.client == "claude-desktop":
|
|
628
|
+
config = self._generate_claude_desktop_config(parsed)
|
|
629
|
+
elif parsed.client == "cursor":
|
|
630
|
+
config = self._generate_cursor_config(parsed)
|
|
631
|
+
elif parsed.client == "vscode":
|
|
632
|
+
config = self._generate_vscode_config(parsed)
|
|
633
|
+
elif parsed.client == "windsurf":
|
|
634
|
+
config = self._generate_windsurf_config(parsed)
|
|
635
|
+
else:
|
|
636
|
+
config = self._generate_claude_desktop_config(parsed)
|
|
637
|
+
|
|
638
|
+
# Output config
|
|
639
|
+
config_json = json.dumps(config, indent=2)
|
|
640
|
+
|
|
641
|
+
if parsed.output:
|
|
642
|
+
with open(parsed.output, 'w') as f:
|
|
643
|
+
f.write(config_json)
|
|
644
|
+
self._print_success(f"Config written to {parsed.output}")
|
|
645
|
+
else:
|
|
646
|
+
print(f"\n[bold]{parsed.client} Configuration:[/bold]\n")
|
|
647
|
+
print(config_json)
|
|
648
|
+
print()
|
|
649
|
+
|
|
650
|
+
return self.EXIT_SUCCESS
|
|
651
|
+
|
|
652
|
+
def _generate_claude_desktop_config(self, args) -> dict:
|
|
653
|
+
"""Generate Claude Desktop config."""
|
|
654
|
+
if args.transport == "stdio":
|
|
655
|
+
return {
|
|
656
|
+
"mcpServers": {
|
|
657
|
+
"praisonai": {
|
|
658
|
+
"command": "praisonai",
|
|
659
|
+
"args": ["mcp", "serve", "--transport", "stdio"],
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
else:
|
|
664
|
+
return {
|
|
665
|
+
"mcpServers": {
|
|
666
|
+
"praisonai": {
|
|
667
|
+
"url": f"http://{args.host}:{args.port}/mcp",
|
|
668
|
+
"transport": "http-stream",
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
def _generate_cursor_config(self, args) -> dict:
|
|
674
|
+
"""Generate Cursor config."""
|
|
675
|
+
if args.transport == "stdio":
|
|
676
|
+
return {
|
|
677
|
+
"mcpServers": {
|
|
678
|
+
"praisonai": {
|
|
679
|
+
"command": "praisonai",
|
|
680
|
+
"args": ["mcp", "serve", "--transport", "stdio"],
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
else:
|
|
685
|
+
return {
|
|
686
|
+
"mcpServers": {
|
|
687
|
+
"praisonai": {
|
|
688
|
+
"url": f"http://{args.host}:{args.port}/mcp",
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
def _generate_vscode_config(self, args) -> dict:
|
|
694
|
+
"""Generate VSCode MCP config."""
|
|
695
|
+
if args.transport == "stdio":
|
|
696
|
+
return {
|
|
697
|
+
"mcp.servers": {
|
|
698
|
+
"praisonai": {
|
|
699
|
+
"command": "praisonai",
|
|
700
|
+
"args": ["mcp", "serve", "--transport", "stdio"],
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
else:
|
|
705
|
+
return {
|
|
706
|
+
"mcp.servers": {
|
|
707
|
+
"praisonai": {
|
|
708
|
+
"url": f"http://{args.host}:{args.port}/mcp",
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
def _generate_windsurf_config(self, args) -> dict:
|
|
714
|
+
"""Generate Windsurf config."""
|
|
715
|
+
return self._generate_cursor_config(args)
|
|
716
|
+
|
|
717
|
+
def cmd_doctor(self, args: List[str]) -> int:
|
|
718
|
+
"""Check MCP server health and configuration."""
|
|
719
|
+
try:
|
|
720
|
+
from .server import PROTOCOL_VERSION, SUPPORTED_VERSIONS
|
|
721
|
+
from .registry import get_tool_registry, get_resource_registry, get_prompt_registry
|
|
722
|
+
from .adapters import register_all
|
|
723
|
+
|
|
724
|
+
print("\n[bold cyan]PraisonAI MCP Server Health Check[/bold cyan]\n")
|
|
725
|
+
|
|
726
|
+
# Register all components
|
|
727
|
+
register_all()
|
|
728
|
+
|
|
729
|
+
# Check protocol version
|
|
730
|
+
print(f"[bold]Protocol Version:[/bold] {PROTOCOL_VERSION}")
|
|
731
|
+
print(f"[bold]Supported Versions:[/bold] {', '.join(SUPPORTED_VERSIONS)}")
|
|
732
|
+
print()
|
|
733
|
+
|
|
734
|
+
# Check registries
|
|
735
|
+
tools = get_tool_registry().list_all()
|
|
736
|
+
resources = get_resource_registry().list_all()
|
|
737
|
+
prompts = get_prompt_registry().list_all()
|
|
738
|
+
|
|
739
|
+
print("[bold]Registered Components:[/bold]")
|
|
740
|
+
print(f" • Tools: {len(tools)}")
|
|
741
|
+
print(f" • Resources: {len(resources)}")
|
|
742
|
+
print(f" • Prompts: {len(prompts)}")
|
|
743
|
+
print()
|
|
744
|
+
|
|
745
|
+
# Check environment
|
|
746
|
+
import os
|
|
747
|
+
env_checks = {
|
|
748
|
+
"OPENAI_API_KEY": bool(os.environ.get("OPENAI_API_KEY")),
|
|
749
|
+
"ANTHROPIC_API_KEY": bool(os.environ.get("ANTHROPIC_API_KEY")),
|
|
750
|
+
"GOOGLE_API_KEY": bool(os.environ.get("GOOGLE_API_KEY")),
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
print("[bold]Environment:[/bold]")
|
|
754
|
+
for key, present in env_checks.items():
|
|
755
|
+
status = "[green]✓[/green]" if present else "[yellow]○[/yellow]"
|
|
756
|
+
print(f" {status} {key}")
|
|
757
|
+
print()
|
|
758
|
+
|
|
759
|
+
# Check dependencies
|
|
760
|
+
deps = {
|
|
761
|
+
"starlette": False,
|
|
762
|
+
"uvicorn": False,
|
|
763
|
+
"praisonaiagents": False,
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
for dep in deps:
|
|
767
|
+
try:
|
|
768
|
+
__import__(dep)
|
|
769
|
+
deps[dep] = True
|
|
770
|
+
except ImportError:
|
|
771
|
+
pass
|
|
772
|
+
|
|
773
|
+
print("[bold]Dependencies:[/bold]")
|
|
774
|
+
for dep, available in deps.items():
|
|
775
|
+
status = "[green]✓[/green]" if available else "[red]✗[/red]"
|
|
776
|
+
print(f" {status} {dep}")
|
|
777
|
+
print()
|
|
778
|
+
|
|
779
|
+
# Overall status
|
|
780
|
+
all_deps = all(deps.values())
|
|
781
|
+
any_api_key = any(env_checks.values())
|
|
782
|
+
|
|
783
|
+
if all_deps and any_api_key:
|
|
784
|
+
self._print_success("MCP server is ready to run")
|
|
785
|
+
elif not all_deps:
|
|
786
|
+
self._print_error("Missing required dependencies. Install with: pip install praisonai[mcp]")
|
|
787
|
+
return self.EXIT_ERROR
|
|
788
|
+
else:
|
|
789
|
+
print("[yellow]Warning: No API keys configured. Some tools may not work.[/yellow]")
|
|
790
|
+
|
|
791
|
+
return self.EXIT_SUCCESS
|
|
792
|
+
|
|
793
|
+
except Exception as e:
|
|
794
|
+
self._print_error(str(e))
|
|
795
|
+
return self.EXIT_ERROR
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
def cmd_serve_recipe(self, args: List[str]) -> int:
|
|
799
|
+
"""Serve a recipe as MCP server."""
|
|
800
|
+
from .recipe_cli import RecipeMCPCLI
|
|
801
|
+
cli = RecipeMCPCLI()
|
|
802
|
+
return cli.cmd_serve_recipe(args)
|
|
803
|
+
|
|
804
|
+
def cmd_list_recipes(self, args: List[str]) -> int:
|
|
805
|
+
"""List available recipes."""
|
|
806
|
+
from .recipe_cli import RecipeMCPCLI
|
|
807
|
+
cli = RecipeMCPCLI()
|
|
808
|
+
return cli.cmd_list_recipes(args)
|
|
809
|
+
|
|
810
|
+
def cmd_validate_recipe(self, args: List[str]) -> int:
|
|
811
|
+
"""Validate recipe MCP compatibility."""
|
|
812
|
+
from .recipe_cli import RecipeMCPCLI
|
|
813
|
+
cli = RecipeMCPCLI()
|
|
814
|
+
return cli.cmd_validate_recipe(args)
|
|
815
|
+
|
|
816
|
+
def cmd_inspect_recipe(self, args: List[str]) -> int:
|
|
817
|
+
"""Inspect recipe MCP schema."""
|
|
818
|
+
from .recipe_cli import RecipeMCPCLI
|
|
819
|
+
cli = RecipeMCPCLI()
|
|
820
|
+
return cli.cmd_inspect_recipe(args)
|
|
821
|
+
|
|
822
|
+
def cmd_config_generate_recipe(self, args: List[str]) -> int:
|
|
823
|
+
"""Generate client config for recipe server."""
|
|
824
|
+
from .recipe_cli import RecipeMCPCLI
|
|
825
|
+
cli = RecipeMCPCLI()
|
|
826
|
+
return cli.cmd_config_generate_recipe(args)
|
|
827
|
+
|
|
828
|
+
def cmd_auth(self, args: List[str]) -> int:
|
|
829
|
+
"""Handle auth subcommands."""
|
|
830
|
+
from .recipe_cli import RecipeMCPCLI
|
|
831
|
+
cli = RecipeMCPCLI()
|
|
832
|
+
return cli.cmd_auth(args)
|
|
833
|
+
|
|
834
|
+
def cmd_tasks(self, args: List[str]) -> int:
|
|
835
|
+
"""Handle tasks subcommands."""
|
|
836
|
+
from .recipe_cli import RecipeMCPCLI
|
|
837
|
+
cli = RecipeMCPCLI()
|
|
838
|
+
return cli.cmd_tasks(args)
|
|
839
|
+
|
|
840
|
+
|
|
841
|
+
def handle_mcp_command(args: List[str]) -> int:
|
|
842
|
+
"""
|
|
843
|
+
Entry point for MCP CLI commands.
|
|
844
|
+
|
|
845
|
+
Args:
|
|
846
|
+
args: Command arguments
|
|
847
|
+
|
|
848
|
+
Returns:
|
|
849
|
+
Exit code
|
|
850
|
+
"""
|
|
851
|
+
cli = MCPServerCLI()
|
|
852
|
+
return cli.handle(args)
|