Skip to content

Commit 14c146e

Browse files
floritangezakahan
andauthored
feat(vefaas): add mcp server (#51)
* test(vefaas): update Unitest of CloudAgentEngine and CloudApp * fix(test): test_cloud typer dependency * test(vefaas): volcenginesdkcore dependency, uv sync --all-extras * test(vefaas): modify chinese annotation * test(vefaas): fix deploy docs * feat(vefaas): add mcp server pre-commit * feat(vefaas): add mcp server pyproject cli * fix(vefaas): fix mcp mount a2a * fix(vefaas): fix run.sh * fix(vefaas): fix app.py pre * fix(vefaas): VeA2AServer add post run_agent to mcp server * fix(vefaas): mcp server in app.py --------- Co-authored-by: tangou <[email protected]> Co-authored-by: hanzhi <[email protected]>
1 parent 189ced9 commit 14c146e

File tree

7 files changed

+105
-13
lines changed

7 files changed

+105
-13
lines changed

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ cli = [
4343
"volcengine-python-sdk==4.0.3", # For Volcengine API
4444
"typer>=0.16.0", # For command-line implementation
4545
"streamlit==1.46.1", # For running VeADK studio app
46-
"agent-pilot-sdk>=0.0.9" # Prompt optimization by Volcengine AgentPilot/PromptPilot toolkits
46+
"agent-pilot-sdk>=0.0.9", # Prompt optimization by Volcengine AgentPilot/PromptPilot toolkits
47+
"fastmcp>=2.11.3", # For running MCP
4748
]
4849
dev = [
4950
"pre-commit>=4.2.0", # Format checking

veadk/a2a/ve_a2a_server.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ def build(self) -> FastAPI:
4848
)
4949
app = app_application.build() # build routes
5050

51-
# import uvicorn
52-
# uvicorn.run(app, host="127.0.0.1", port=8000)
5351
return app
5452

5553

veadk/cli/main.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,14 @@ def init():
9898
)
9999

100100
deploy_mode_options = {
101-
"1": "A2A Server",
101+
"1": "A2A/MCP Server",
102102
"2": "VeADK Studio",
103103
"3": "VeADK Web / Google ADK Web",
104104
}
105105

106106
deploy_mode = Prompt.ask(
107107
"""Choose your deploy mode:
108-
1. A2A Server
108+
1. A2A/MCP Server
109109
2. VeADK Studio
110110
3. VeADK Web / Google ADK Web
111111
""",

veadk/cli/services/vefaas/template/deploy.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
import asyncio
1616
from pathlib import Path
1717

18+
1819
from veadk.cloud.cloud_agent_engine import CloudAgentEngine
20+
from fastmcp.client import Client
1921

2022
SESSION_ID = "cloud_app_test_session"
2123
USER_ID = "cloud_app_test_user"
@@ -30,7 +32,6 @@
3032

3133
async def main():
3234
engine = CloudAgentEngine()
33-
3435
cloud_app = engine.deploy(
3536
path=str(Path(__file__).parent / "src"),
3637
application_name=VEFAAS_APPLICATION_NAME,
@@ -40,16 +41,42 @@ async def main():
4041
use_studio=USE_STUDIO,
4142
use_adk_web=USE_ADK_WEB,
4243
)
43-
44-
if not USE_STUDIO and not USE_ADK_WEB:
44+
query_example = "How is the weather like in Beijing?"
45+
if not USE_STUDIO and (not USE_ADK_WEB):
46+
print("### A2A example ###")
4547
response_message = await cloud_app.message_send(
46-
"How is the weather like in Beijing?", SESSION_ID, USER_ID
48+
query_example, SESSION_ID, USER_ID
4749
)
4850
print(f"VeFaaS application ID: {cloud_app.vefaas_application_id}")
4951
print(f"Message ID: {response_message.messageId}")
5052
print(
5153
f"Response from {cloud_app.vefaas_endpoint}: {response_message.parts[0].root.text}"
5254
)
55+
56+
print("### MCP example ###")
57+
# cloud_app = CloudApp(vefaas_application_name=VEFAAS_APPLICATION_NAME)
58+
endpoint = cloud_app._get_vefaas_endpoint()
59+
print(f"endpoint:{endpoint}")
60+
# Connect to MCP server
61+
client = Client(f"{endpoint}/mcp")
62+
63+
async with client:
64+
# List available tools
65+
tools = await client.list_tools()
66+
print(f"tools: {tools}\n")
67+
68+
# Call run_agent tool, pass user input and session information
69+
res = await client.call_tool(
70+
"run_agent",
71+
{
72+
"user_input": query_example,
73+
"session_id": SESSION_ID,
74+
"user_id": USER_ID,
75+
},
76+
)
77+
print(f"VeFaaS application ID: {cloud_app.vefaas_application_id}")
78+
print(f"Response from {cloud_app.vefaas_endpoint}: {res}")
79+
5380
else:
5481
print(f"Web is running at: {cloud_app.vefaas_endpoint}")
5582

veadk/cli/services/vefaas/template/src/app.py

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@
1313
# limitations under the License.
1414

1515
import os
16-
1716
from agent import agent, app_name, short_term_memory
1817
from veadk.a2a.ve_a2a_server import init_app
1918
from veadk.tracing.base_tracer import BaseTracer
2019
from veadk.tracing.telemetry.opentelemetry_tracer import OpentelemetryTracer
20+
from veadk.runner import Runner
21+
from contextlib import asynccontextmanager
22+
from fastmcp import FastMCP
23+
from fastapi import FastAPI
2124

2225

2326
# ==============================================================================
@@ -62,9 +65,69 @@
6265
# Tracer Config ================================================================
6366
# ==============================================================================
6467

65-
app = init_app(
66-
server_url="0.0.0.0", # Automatic identification is not supported yet.
68+
# Create A2A app
69+
a2a_app = init_app(
70+
server_url="0.0.0.0",
6771
app_name=app_name,
6872
agent=agent,
6973
short_term_memory=short_term_memory,
7074
)
75+
76+
# Add a2a app to fastmcp
77+
runner = Runner(
78+
agent=agent,
79+
short_term_memory=short_term_memory,
80+
app_name=app_name,
81+
user_id="",
82+
)
83+
84+
85+
# mcp server
86+
@a2a_app.post("/run_agent", operation_id="run_agent", tags=["mcp"])
87+
async def run_agent(
88+
user_input: str,
89+
user_id: str = "unknown_user",
90+
session_id: str = "unknown_session",
91+
) -> str:
92+
"""
93+
Execute agent with user input and return final output
94+
Args:
95+
user_input: User's input message
96+
user_id: User identifier
97+
session_id: Session identifier
98+
Returns:
99+
Final agent response
100+
"""
101+
# Set user_id for runner
102+
runner.user_id = user_id
103+
104+
# Running agent and get final output
105+
final_output = await runner.run(
106+
messages=user_input,
107+
session_id=session_id,
108+
)
109+
return final_output
110+
111+
112+
mcp = FastMCP.from_fastapi(app=a2a_app, name=app_name, include_tags={"mcp"})
113+
114+
# Create MCP ASGI app
115+
mcp_app = mcp.http_app(path="/")
116+
117+
118+
# Combined lifespan management
119+
@asynccontextmanager
120+
async def combined_lifespan(app: FastAPI):
121+
async with mcp_app.lifespan(app):
122+
yield
123+
124+
125+
# Create main FastAPI app with combined lifespan
126+
app = FastAPI(title=a2a_app.title, version=a2a_app.version, lifespan=combined_lifespan)
127+
128+
# Mount A2A routes to main app
129+
for route in a2a_app.routes:
130+
app.routes.append(route)
131+
132+
# Mount MCP server at /mcp endpoint
133+
app.mount("/mcp", mcp_app)

veadk/cli/services/vefaas/template/src/requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ opensearch-py==2.8.0
33
agent-pilot-sdk>=0.0.9 # extra dep for prompt optimization in veadk studio
44
typer>=0.16.0
55
uvicorn[standard]
6-
fastapi
6+
fastapi
7+
fastmcp

veadk/cli/services/vefaas/template/src/run.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ python3 -m pip install uvicorn[standard]
3838

3939
python3 -m pip install fastapi
4040

41+
python3 -m pip install fastmcp
42+
4143
USE_STUDIO=${USE_STUDIO:-False}
4244
USE_ADK_WEB=${USE_ADK_WEB:-False}
4345

0 commit comments

Comments
 (0)