Skip to content

Commit 4428e98

Browse files
committed
Remove temporary debug workflow - tests now passing
1 parent b934cc6 commit 4428e98

22 files changed

Lines changed: 6359 additions & 70 deletions

.github/workflows/test-quick-debug.yml

Lines changed: 0 additions & 68 deletions
This file was deleted.

src/praisonai/praisonai/cli/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1411,6 +1411,7 @@ def parse_args(self):
14111411
handler = PackageHandler()
14121412
exit_code = handler.cmd_uninstall(unknown_args)
14131413
sys.exit(exit_code)
1414+
14141415

14151416
# Only check framework availability for agent-related operations
14161417
if not args.command and (args.init or args.auto or args.framework):

src/praisonai/praisonai/mcp_server/__init__.py

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@
33
44
Exposes PraisonAI capabilities as an MCP server that any MCP client can connect to.
55
6+
MCP Protocol Version: 2025-11-25
7+
68
Supports:
79
- STDIO transport (default, for Claude Desktop, Cursor, etc.)
8-
- HTTP Stream transport (MCP 2025-03-26 spec)
10+
- HTTP Stream transport (MCP 2025-11-25 spec)
11+
- Recipe-to-MCP server bridge
12+
- Tasks API (experimental)
13+
- Elicitation (form and URL modes)
14+
- OAuth 2.1 / OpenID Connect authentication
15+
- Icons and rich metadata
916
1017
Usage:
1118
# STDIO mode (for Claude Desktop config)
@@ -14,26 +21,57 @@
1421
# HTTP Stream mode
1522
praisonai mcp serve --transport http-stream --port 8080
1623
24+
# Serve a recipe as MCP server
25+
praisonai mcp serve-recipe support-reply --transport stdio
26+
1727
# Programmatic usage
18-
from praisonai.mcp_server import MCPServer
28+
from praisonai.mcp_server import MCPServer, RecipeMCPAdapter
1929
2030
server = MCPServer()
2131
server.run(transport="stdio")
32+
33+
# Recipe as MCP server
34+
adapter = RecipeMCPAdapter("support-reply")
35+
adapter.load()
36+
server = adapter.to_mcp_server()
37+
server.run(transport="stdio")
2238
"""
2339

2440
__all__ = [
41+
# Core server
2542
"MCPServer",
2643
"MCPToolRegistry",
2744
"MCPResourceRegistry",
2845
"MCPPromptRegistry",
2946
"register_tool",
3047
"register_resource",
3148
"register_prompt",
49+
# Recipe adapter
50+
"RecipeMCPAdapter",
51+
"RecipeMCPConfig",
52+
"create_recipe_mcp_server",
53+
# Tasks API
54+
"TaskManager",
55+
"TaskStore",
56+
"Task",
57+
"TaskState",
58+
# Elicitation
59+
"ElicitationHandler",
60+
"ElicitationRequest",
61+
"ElicitationResult",
62+
# Sampling
63+
"SamplingHandler",
64+
"SamplingRequest",
65+
"SamplingResponse",
66+
# Icons
67+
"IconMetadata",
68+
"RichMetadata",
3269
]
3370

3471

3572
def __getattr__(name):
3673
"""Lazy load server components."""
74+
# Core server
3775
if name == "MCPServer":
3876
from .server import MCPServer
3977
return MCPServer
@@ -55,4 +93,60 @@ def __getattr__(name):
5593
elif name == "register_prompt":
5694
from .registry import register_prompt
5795
return register_prompt
96+
97+
# Recipe adapter
98+
elif name == "RecipeMCPAdapter":
99+
from .recipe_adapter import RecipeMCPAdapter
100+
return RecipeMCPAdapter
101+
elif name == "RecipeMCPConfig":
102+
from .recipe_adapter import RecipeMCPConfig
103+
return RecipeMCPConfig
104+
elif name == "create_recipe_mcp_server":
105+
from .recipe_adapter import create_recipe_mcp_server
106+
return create_recipe_mcp_server
107+
108+
# Tasks API
109+
elif name == "TaskManager":
110+
from .tasks import TaskManager
111+
return TaskManager
112+
elif name == "TaskStore":
113+
from .tasks import TaskStore
114+
return TaskStore
115+
elif name == "Task":
116+
from .tasks import Task
117+
return Task
118+
elif name == "TaskState":
119+
from .tasks import TaskState
120+
return TaskState
121+
122+
# Elicitation
123+
elif name == "ElicitationHandler":
124+
from .elicitation import ElicitationHandler
125+
return ElicitationHandler
126+
elif name == "ElicitationRequest":
127+
from .elicitation import ElicitationRequest
128+
return ElicitationRequest
129+
elif name == "ElicitationResult":
130+
from .elicitation import ElicitationResult
131+
return ElicitationResult
132+
133+
# Sampling
134+
elif name == "SamplingHandler":
135+
from .sampling import SamplingHandler
136+
return SamplingHandler
137+
elif name == "SamplingRequest":
138+
from .sampling import SamplingRequest
139+
return SamplingRequest
140+
elif name == "SamplingResponse":
141+
from .sampling import SamplingResponse
142+
return SamplingResponse
143+
144+
# Icons
145+
elif name == "IconMetadata":
146+
from .icons import IconMetadata
147+
return IconMetadata
148+
elif name == "RichMetadata":
149+
from .icons import RichMetadata
150+
return RichMetadata
151+
58152
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"""
2+
MCP Authentication and Authorization Module
3+
4+
Implements OAuth 2.1 and OpenID Connect support per MCP 2025-11-25 specification.
5+
6+
Features:
7+
- API Key authentication
8+
- OAuth 2.1 authorization framework
9+
- OpenID Connect Discovery
10+
- Client ID Metadata Documents
11+
- Incremental scope handling
12+
- WWW-Authenticate challenges
13+
"""
14+
15+
from typing import TYPE_CHECKING
16+
17+
if TYPE_CHECKING:
18+
from .oauth import OAuthConfig, OAuthManager
19+
from .oidc import OIDCDiscovery, OIDCConfig
20+
from .api_key import APIKeyAuth
21+
from .scopes import ScopeManager, ScopeChallenge
22+
23+
__all__ = [
24+
"OAuthConfig",
25+
"OAuthManager",
26+
"OIDCDiscovery",
27+
"OIDCConfig",
28+
"APIKeyAuth",
29+
"ScopeManager",
30+
"ScopeChallenge",
31+
]
32+
33+
34+
def __getattr__(name: str):
35+
"""Lazy load auth components."""
36+
if name in ("OAuthConfig", "OAuthManager"):
37+
from .oauth import OAuthConfig, OAuthManager
38+
return OAuthConfig if name == "OAuthConfig" else OAuthManager
39+
elif name in ("OIDCDiscovery", "OIDCConfig"):
40+
from .oidc import OIDCDiscovery, OIDCConfig
41+
return OIDCDiscovery if name == "OIDCDiscovery" else OIDCConfig
42+
elif name == "APIKeyAuth":
43+
from .api_key import APIKeyAuth
44+
return APIKeyAuth
45+
elif name in ("ScopeManager", "ScopeChallenge"):
46+
from .scopes import ScopeManager, ScopeChallenge
47+
return ScopeManager if name == "ScopeManager" else ScopeChallenge
48+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

0 commit comments

Comments
 (0)