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.
Files changed (393) hide show
  1. praisonai/__init__.py +54 -0
  2. praisonai/__main__.py +15 -0
  3. praisonai/acp/__init__.py +54 -0
  4. praisonai/acp/config.py +159 -0
  5. praisonai/acp/server.py +587 -0
  6. praisonai/acp/session.py +219 -0
  7. praisonai/adapters/__init__.py +50 -0
  8. praisonai/adapters/readers.py +395 -0
  9. praisonai/adapters/rerankers.py +315 -0
  10. praisonai/adapters/retrievers.py +394 -0
  11. praisonai/adapters/vector_stores.py +409 -0
  12. praisonai/agent_scheduler.py +337 -0
  13. praisonai/agents_generator.py +903 -0
  14. praisonai/api/call.py +292 -0
  15. praisonai/auto.py +1197 -0
  16. praisonai/capabilities/__init__.py +275 -0
  17. praisonai/capabilities/a2a.py +140 -0
  18. praisonai/capabilities/assistants.py +283 -0
  19. praisonai/capabilities/audio.py +320 -0
  20. praisonai/capabilities/batches.py +469 -0
  21. praisonai/capabilities/completions.py +336 -0
  22. praisonai/capabilities/container_files.py +155 -0
  23. praisonai/capabilities/containers.py +93 -0
  24. praisonai/capabilities/embeddings.py +158 -0
  25. praisonai/capabilities/files.py +467 -0
  26. praisonai/capabilities/fine_tuning.py +293 -0
  27. praisonai/capabilities/guardrails.py +182 -0
  28. praisonai/capabilities/images.py +330 -0
  29. praisonai/capabilities/mcp.py +190 -0
  30. praisonai/capabilities/messages.py +270 -0
  31. praisonai/capabilities/moderations.py +154 -0
  32. praisonai/capabilities/ocr.py +217 -0
  33. praisonai/capabilities/passthrough.py +204 -0
  34. praisonai/capabilities/rag.py +207 -0
  35. praisonai/capabilities/realtime.py +160 -0
  36. praisonai/capabilities/rerank.py +165 -0
  37. praisonai/capabilities/responses.py +266 -0
  38. praisonai/capabilities/search.py +109 -0
  39. praisonai/capabilities/skills.py +133 -0
  40. praisonai/capabilities/vector_store_files.py +334 -0
  41. praisonai/capabilities/vector_stores.py +304 -0
  42. praisonai/capabilities/videos.py +141 -0
  43. praisonai/chainlit_ui.py +304 -0
  44. praisonai/chat/__init__.py +106 -0
  45. praisonai/chat/app.py +125 -0
  46. praisonai/cli/__init__.py +26 -0
  47. praisonai/cli/app.py +213 -0
  48. praisonai/cli/commands/__init__.py +75 -0
  49. praisonai/cli/commands/acp.py +70 -0
  50. praisonai/cli/commands/completion.py +333 -0
  51. praisonai/cli/commands/config.py +166 -0
  52. praisonai/cli/commands/debug.py +142 -0
  53. praisonai/cli/commands/diag.py +55 -0
  54. praisonai/cli/commands/doctor.py +166 -0
  55. praisonai/cli/commands/environment.py +179 -0
  56. praisonai/cli/commands/lsp.py +112 -0
  57. praisonai/cli/commands/mcp.py +210 -0
  58. praisonai/cli/commands/profile.py +457 -0
  59. praisonai/cli/commands/run.py +228 -0
  60. praisonai/cli/commands/schedule.py +150 -0
  61. praisonai/cli/commands/serve.py +97 -0
  62. praisonai/cli/commands/session.py +212 -0
  63. praisonai/cli/commands/traces.py +145 -0
  64. praisonai/cli/commands/version.py +101 -0
  65. praisonai/cli/configuration/__init__.py +18 -0
  66. praisonai/cli/configuration/loader.py +353 -0
  67. praisonai/cli/configuration/paths.py +114 -0
  68. praisonai/cli/configuration/schema.py +164 -0
  69. praisonai/cli/features/__init__.py +268 -0
  70. praisonai/cli/features/acp.py +236 -0
  71. praisonai/cli/features/action_orchestrator.py +546 -0
  72. praisonai/cli/features/agent_scheduler.py +773 -0
  73. praisonai/cli/features/agent_tools.py +474 -0
  74. praisonai/cli/features/agents.py +375 -0
  75. praisonai/cli/features/at_mentions.py +471 -0
  76. praisonai/cli/features/auto_memory.py +182 -0
  77. praisonai/cli/features/autonomy_mode.py +490 -0
  78. praisonai/cli/features/background.py +356 -0
  79. praisonai/cli/features/base.py +168 -0
  80. praisonai/cli/features/capabilities.py +1326 -0
  81. praisonai/cli/features/checkpoints.py +338 -0
  82. praisonai/cli/features/code_intelligence.py +652 -0
  83. praisonai/cli/features/compaction.py +294 -0
  84. praisonai/cli/features/compare.py +534 -0
  85. praisonai/cli/features/cost_tracker.py +514 -0
  86. praisonai/cli/features/debug.py +810 -0
  87. praisonai/cli/features/deploy.py +517 -0
  88. praisonai/cli/features/diag.py +289 -0
  89. praisonai/cli/features/doctor/__init__.py +63 -0
  90. praisonai/cli/features/doctor/checks/__init__.py +24 -0
  91. praisonai/cli/features/doctor/checks/acp_checks.py +240 -0
  92. praisonai/cli/features/doctor/checks/config_checks.py +366 -0
  93. praisonai/cli/features/doctor/checks/db_checks.py +366 -0
  94. praisonai/cli/features/doctor/checks/env_checks.py +543 -0
  95. praisonai/cli/features/doctor/checks/lsp_checks.py +199 -0
  96. praisonai/cli/features/doctor/checks/mcp_checks.py +349 -0
  97. praisonai/cli/features/doctor/checks/memory_checks.py +268 -0
  98. praisonai/cli/features/doctor/checks/network_checks.py +251 -0
  99. praisonai/cli/features/doctor/checks/obs_checks.py +328 -0
  100. praisonai/cli/features/doctor/checks/performance_checks.py +235 -0
  101. praisonai/cli/features/doctor/checks/permissions_checks.py +259 -0
  102. praisonai/cli/features/doctor/checks/selftest_checks.py +322 -0
  103. praisonai/cli/features/doctor/checks/serve_checks.py +426 -0
  104. praisonai/cli/features/doctor/checks/skills_checks.py +231 -0
  105. praisonai/cli/features/doctor/checks/tools_checks.py +371 -0
  106. praisonai/cli/features/doctor/engine.py +266 -0
  107. praisonai/cli/features/doctor/formatters.py +310 -0
  108. praisonai/cli/features/doctor/handler.py +397 -0
  109. praisonai/cli/features/doctor/models.py +264 -0
  110. praisonai/cli/features/doctor/registry.py +239 -0
  111. praisonai/cli/features/endpoints.py +1019 -0
  112. praisonai/cli/features/eval.py +560 -0
  113. praisonai/cli/features/external_agents.py +231 -0
  114. praisonai/cli/features/fast_context.py +410 -0
  115. praisonai/cli/features/flow_display.py +566 -0
  116. praisonai/cli/features/git_integration.py +651 -0
  117. praisonai/cli/features/guardrail.py +171 -0
  118. praisonai/cli/features/handoff.py +185 -0
  119. praisonai/cli/features/hooks.py +583 -0
  120. praisonai/cli/features/image.py +384 -0
  121. praisonai/cli/features/interactive_runtime.py +585 -0
  122. praisonai/cli/features/interactive_tools.py +380 -0
  123. praisonai/cli/features/interactive_tui.py +603 -0
  124. praisonai/cli/features/jobs.py +632 -0
  125. praisonai/cli/features/knowledge.py +531 -0
  126. praisonai/cli/features/lite.py +244 -0
  127. praisonai/cli/features/lsp_cli.py +225 -0
  128. praisonai/cli/features/mcp.py +169 -0
  129. praisonai/cli/features/message_queue.py +587 -0
  130. praisonai/cli/features/metrics.py +211 -0
  131. praisonai/cli/features/n8n.py +673 -0
  132. praisonai/cli/features/observability.py +293 -0
  133. praisonai/cli/features/ollama.py +361 -0
  134. praisonai/cli/features/output_style.py +273 -0
  135. praisonai/cli/features/package.py +631 -0
  136. praisonai/cli/features/performance.py +308 -0
  137. praisonai/cli/features/persistence.py +636 -0
  138. praisonai/cli/features/profile.py +226 -0
  139. praisonai/cli/features/profiler/__init__.py +81 -0
  140. praisonai/cli/features/profiler/core.py +558 -0
  141. praisonai/cli/features/profiler/optimizations.py +652 -0
  142. praisonai/cli/features/profiler/suite.py +386 -0
  143. praisonai/cli/features/profiling.py +350 -0
  144. praisonai/cli/features/queue/__init__.py +73 -0
  145. praisonai/cli/features/queue/manager.py +395 -0
  146. praisonai/cli/features/queue/models.py +286 -0
  147. praisonai/cli/features/queue/persistence.py +564 -0
  148. praisonai/cli/features/queue/scheduler.py +484 -0
  149. praisonai/cli/features/queue/worker.py +372 -0
  150. praisonai/cli/features/recipe.py +1723 -0
  151. praisonai/cli/features/recipes.py +449 -0
  152. praisonai/cli/features/registry.py +229 -0
  153. praisonai/cli/features/repo_map.py +860 -0
  154. praisonai/cli/features/router.py +466 -0
  155. praisonai/cli/features/sandbox_executor.py +515 -0
  156. praisonai/cli/features/serve.py +829 -0
  157. praisonai/cli/features/session.py +222 -0
  158. praisonai/cli/features/skills.py +856 -0
  159. praisonai/cli/features/slash_commands.py +650 -0
  160. praisonai/cli/features/telemetry.py +179 -0
  161. praisonai/cli/features/templates.py +1384 -0
  162. praisonai/cli/features/thinking.py +305 -0
  163. praisonai/cli/features/todo.py +334 -0
  164. praisonai/cli/features/tools.py +680 -0
  165. praisonai/cli/features/tui/__init__.py +83 -0
  166. praisonai/cli/features/tui/app.py +580 -0
  167. praisonai/cli/features/tui/cli.py +566 -0
  168. praisonai/cli/features/tui/debug.py +511 -0
  169. praisonai/cli/features/tui/events.py +99 -0
  170. praisonai/cli/features/tui/mock_provider.py +328 -0
  171. praisonai/cli/features/tui/orchestrator.py +652 -0
  172. praisonai/cli/features/tui/screens/__init__.py +50 -0
  173. praisonai/cli/features/tui/screens/main.py +245 -0
  174. praisonai/cli/features/tui/screens/queue.py +174 -0
  175. praisonai/cli/features/tui/screens/session.py +124 -0
  176. praisonai/cli/features/tui/screens/settings.py +148 -0
  177. praisonai/cli/features/tui/widgets/__init__.py +56 -0
  178. praisonai/cli/features/tui/widgets/chat.py +261 -0
  179. praisonai/cli/features/tui/widgets/composer.py +224 -0
  180. praisonai/cli/features/tui/widgets/queue_panel.py +200 -0
  181. praisonai/cli/features/tui/widgets/status.py +167 -0
  182. praisonai/cli/features/tui/widgets/tool_panel.py +248 -0
  183. praisonai/cli/features/workflow.py +720 -0
  184. praisonai/cli/legacy.py +236 -0
  185. praisonai/cli/main.py +5559 -0
  186. praisonai/cli/schedule_cli.py +54 -0
  187. praisonai/cli/state/__init__.py +31 -0
  188. praisonai/cli/state/identifiers.py +161 -0
  189. praisonai/cli/state/sessions.py +313 -0
  190. praisonai/code/__init__.py +93 -0
  191. praisonai/code/agent_tools.py +344 -0
  192. praisonai/code/diff/__init__.py +21 -0
  193. praisonai/code/diff/diff_strategy.py +432 -0
  194. praisonai/code/tools/__init__.py +27 -0
  195. praisonai/code/tools/apply_diff.py +221 -0
  196. praisonai/code/tools/execute_command.py +275 -0
  197. praisonai/code/tools/list_files.py +274 -0
  198. praisonai/code/tools/read_file.py +206 -0
  199. praisonai/code/tools/search_replace.py +248 -0
  200. praisonai/code/tools/write_file.py +217 -0
  201. praisonai/code/utils/__init__.py +46 -0
  202. praisonai/code/utils/file_utils.py +307 -0
  203. praisonai/code/utils/ignore_utils.py +308 -0
  204. praisonai/code/utils/text_utils.py +276 -0
  205. praisonai/db/__init__.py +64 -0
  206. praisonai/db/adapter.py +531 -0
  207. praisonai/deploy/__init__.py +62 -0
  208. praisonai/deploy/api.py +231 -0
  209. praisonai/deploy/docker.py +454 -0
  210. praisonai/deploy/doctor.py +367 -0
  211. praisonai/deploy/main.py +327 -0
  212. praisonai/deploy/models.py +179 -0
  213. praisonai/deploy/providers/__init__.py +33 -0
  214. praisonai/deploy/providers/aws.py +331 -0
  215. praisonai/deploy/providers/azure.py +358 -0
  216. praisonai/deploy/providers/base.py +101 -0
  217. praisonai/deploy/providers/gcp.py +314 -0
  218. praisonai/deploy/schema.py +208 -0
  219. praisonai/deploy.py +185 -0
  220. praisonai/endpoints/__init__.py +53 -0
  221. praisonai/endpoints/a2u_server.py +410 -0
  222. praisonai/endpoints/discovery.py +165 -0
  223. praisonai/endpoints/providers/__init__.py +28 -0
  224. praisonai/endpoints/providers/a2a.py +253 -0
  225. praisonai/endpoints/providers/a2u.py +208 -0
  226. praisonai/endpoints/providers/agents_api.py +171 -0
  227. praisonai/endpoints/providers/base.py +231 -0
  228. praisonai/endpoints/providers/mcp.py +263 -0
  229. praisonai/endpoints/providers/recipe.py +206 -0
  230. praisonai/endpoints/providers/tools_mcp.py +150 -0
  231. praisonai/endpoints/registry.py +131 -0
  232. praisonai/endpoints/server.py +161 -0
  233. praisonai/inbuilt_tools/__init__.py +24 -0
  234. praisonai/inbuilt_tools/autogen_tools.py +117 -0
  235. praisonai/inc/__init__.py +2 -0
  236. praisonai/inc/config.py +96 -0
  237. praisonai/inc/models.py +155 -0
  238. praisonai/integrations/__init__.py +56 -0
  239. praisonai/integrations/base.py +303 -0
  240. praisonai/integrations/claude_code.py +270 -0
  241. praisonai/integrations/codex_cli.py +255 -0
  242. praisonai/integrations/cursor_cli.py +195 -0
  243. praisonai/integrations/gemini_cli.py +222 -0
  244. praisonai/jobs/__init__.py +67 -0
  245. praisonai/jobs/executor.py +425 -0
  246. praisonai/jobs/models.py +230 -0
  247. praisonai/jobs/router.py +314 -0
  248. praisonai/jobs/server.py +186 -0
  249. praisonai/jobs/store.py +203 -0
  250. praisonai/llm/__init__.py +66 -0
  251. praisonai/llm/registry.py +382 -0
  252. praisonai/mcp_server/__init__.py +152 -0
  253. praisonai/mcp_server/adapters/__init__.py +74 -0
  254. praisonai/mcp_server/adapters/agents.py +128 -0
  255. praisonai/mcp_server/adapters/capabilities.py +168 -0
  256. praisonai/mcp_server/adapters/cli_tools.py +568 -0
  257. praisonai/mcp_server/adapters/extended_capabilities.py +462 -0
  258. praisonai/mcp_server/adapters/knowledge.py +93 -0
  259. praisonai/mcp_server/adapters/memory.py +104 -0
  260. praisonai/mcp_server/adapters/prompts.py +306 -0
  261. praisonai/mcp_server/adapters/resources.py +124 -0
  262. praisonai/mcp_server/adapters/tools_bridge.py +280 -0
  263. praisonai/mcp_server/auth/__init__.py +48 -0
  264. praisonai/mcp_server/auth/api_key.py +291 -0
  265. praisonai/mcp_server/auth/oauth.py +460 -0
  266. praisonai/mcp_server/auth/oidc.py +289 -0
  267. praisonai/mcp_server/auth/scopes.py +260 -0
  268. praisonai/mcp_server/cli.py +852 -0
  269. praisonai/mcp_server/elicitation.py +445 -0
  270. praisonai/mcp_server/icons.py +302 -0
  271. praisonai/mcp_server/recipe_adapter.py +573 -0
  272. praisonai/mcp_server/recipe_cli.py +824 -0
  273. praisonai/mcp_server/registry.py +703 -0
  274. praisonai/mcp_server/sampling.py +422 -0
  275. praisonai/mcp_server/server.py +490 -0
  276. praisonai/mcp_server/tasks.py +443 -0
  277. praisonai/mcp_server/transports/__init__.py +18 -0
  278. praisonai/mcp_server/transports/http_stream.py +376 -0
  279. praisonai/mcp_server/transports/stdio.py +132 -0
  280. praisonai/persistence/__init__.py +84 -0
  281. praisonai/persistence/config.py +238 -0
  282. praisonai/persistence/conversation/__init__.py +25 -0
  283. praisonai/persistence/conversation/async_mysql.py +427 -0
  284. praisonai/persistence/conversation/async_postgres.py +410 -0
  285. praisonai/persistence/conversation/async_sqlite.py +371 -0
  286. praisonai/persistence/conversation/base.py +151 -0
  287. praisonai/persistence/conversation/json_store.py +250 -0
  288. praisonai/persistence/conversation/mysql.py +387 -0
  289. praisonai/persistence/conversation/postgres.py +401 -0
  290. praisonai/persistence/conversation/singlestore.py +240 -0
  291. praisonai/persistence/conversation/sqlite.py +341 -0
  292. praisonai/persistence/conversation/supabase.py +203 -0
  293. praisonai/persistence/conversation/surrealdb.py +287 -0
  294. praisonai/persistence/factory.py +301 -0
  295. praisonai/persistence/hooks/__init__.py +18 -0
  296. praisonai/persistence/hooks/agent_hooks.py +297 -0
  297. praisonai/persistence/knowledge/__init__.py +26 -0
  298. praisonai/persistence/knowledge/base.py +144 -0
  299. praisonai/persistence/knowledge/cassandra.py +232 -0
  300. praisonai/persistence/knowledge/chroma.py +295 -0
  301. praisonai/persistence/knowledge/clickhouse.py +242 -0
  302. praisonai/persistence/knowledge/cosmosdb_vector.py +438 -0
  303. praisonai/persistence/knowledge/couchbase.py +286 -0
  304. praisonai/persistence/knowledge/lancedb.py +216 -0
  305. praisonai/persistence/knowledge/langchain_adapter.py +291 -0
  306. praisonai/persistence/knowledge/lightrag_adapter.py +212 -0
  307. praisonai/persistence/knowledge/llamaindex_adapter.py +256 -0
  308. praisonai/persistence/knowledge/milvus.py +277 -0
  309. praisonai/persistence/knowledge/mongodb_vector.py +306 -0
  310. praisonai/persistence/knowledge/pgvector.py +335 -0
  311. praisonai/persistence/knowledge/pinecone.py +253 -0
  312. praisonai/persistence/knowledge/qdrant.py +301 -0
  313. praisonai/persistence/knowledge/redis_vector.py +291 -0
  314. praisonai/persistence/knowledge/singlestore_vector.py +299 -0
  315. praisonai/persistence/knowledge/surrealdb_vector.py +309 -0
  316. praisonai/persistence/knowledge/upstash_vector.py +266 -0
  317. praisonai/persistence/knowledge/weaviate.py +223 -0
  318. praisonai/persistence/migrations/__init__.py +10 -0
  319. praisonai/persistence/migrations/manager.py +251 -0
  320. praisonai/persistence/orchestrator.py +406 -0
  321. praisonai/persistence/state/__init__.py +21 -0
  322. praisonai/persistence/state/async_mongodb.py +200 -0
  323. praisonai/persistence/state/base.py +107 -0
  324. praisonai/persistence/state/dynamodb.py +226 -0
  325. praisonai/persistence/state/firestore.py +175 -0
  326. praisonai/persistence/state/gcs.py +155 -0
  327. praisonai/persistence/state/memory.py +245 -0
  328. praisonai/persistence/state/mongodb.py +158 -0
  329. praisonai/persistence/state/redis.py +190 -0
  330. praisonai/persistence/state/upstash.py +144 -0
  331. praisonai/persistence/tests/__init__.py +3 -0
  332. praisonai/persistence/tests/test_all_backends.py +633 -0
  333. praisonai/profiler.py +1214 -0
  334. praisonai/recipe/__init__.py +134 -0
  335. praisonai/recipe/bridge.py +278 -0
  336. praisonai/recipe/core.py +893 -0
  337. praisonai/recipe/exceptions.py +54 -0
  338. praisonai/recipe/history.py +402 -0
  339. praisonai/recipe/models.py +266 -0
  340. praisonai/recipe/operations.py +440 -0
  341. praisonai/recipe/policy.py +422 -0
  342. praisonai/recipe/registry.py +849 -0
  343. praisonai/recipe/runtime.py +214 -0
  344. praisonai/recipe/security.py +711 -0
  345. praisonai/recipe/serve.py +859 -0
  346. praisonai/recipe/server.py +613 -0
  347. praisonai/scheduler/__init__.py +45 -0
  348. praisonai/scheduler/agent_scheduler.py +552 -0
  349. praisonai/scheduler/base.py +124 -0
  350. praisonai/scheduler/daemon_manager.py +225 -0
  351. praisonai/scheduler/state_manager.py +155 -0
  352. praisonai/scheduler/yaml_loader.py +193 -0
  353. praisonai/scheduler.py +194 -0
  354. praisonai/setup/__init__.py +1 -0
  355. praisonai/setup/build.py +21 -0
  356. praisonai/setup/post_install.py +23 -0
  357. praisonai/setup/setup_conda_env.py +25 -0
  358. praisonai/setup.py +16 -0
  359. praisonai/templates/__init__.py +116 -0
  360. praisonai/templates/cache.py +364 -0
  361. praisonai/templates/dependency_checker.py +358 -0
  362. praisonai/templates/discovery.py +391 -0
  363. praisonai/templates/loader.py +564 -0
  364. praisonai/templates/registry.py +511 -0
  365. praisonai/templates/resolver.py +206 -0
  366. praisonai/templates/security.py +327 -0
  367. praisonai/templates/tool_override.py +498 -0
  368. praisonai/templates/tools_doctor.py +256 -0
  369. praisonai/test.py +105 -0
  370. praisonai/train.py +562 -0
  371. praisonai/train_vision.py +306 -0
  372. praisonai/ui/agents.py +824 -0
  373. praisonai/ui/callbacks.py +57 -0
  374. praisonai/ui/chainlit_compat.py +246 -0
  375. praisonai/ui/chat.py +532 -0
  376. praisonai/ui/code.py +717 -0
  377. praisonai/ui/colab.py +474 -0
  378. praisonai/ui/colab_chainlit.py +81 -0
  379. praisonai/ui/components/aicoder.py +284 -0
  380. praisonai/ui/context.py +283 -0
  381. praisonai/ui/database_config.py +56 -0
  382. praisonai/ui/db.py +294 -0
  383. praisonai/ui/realtime.py +488 -0
  384. praisonai/ui/realtimeclient/__init__.py +756 -0
  385. praisonai/ui/realtimeclient/tools.py +242 -0
  386. praisonai/ui/sql_alchemy.py +710 -0
  387. praisonai/upload_vision.py +140 -0
  388. praisonai/version.py +1 -0
  389. praisonai-3.0.0.dist-info/METADATA +3493 -0
  390. praisonai-3.0.0.dist-info/RECORD +393 -0
  391. praisonai-3.0.0.dist-info/WHEEL +5 -0
  392. praisonai-3.0.0.dist-info/entry_points.txt +4 -0
  393. 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)