Skip to content

Commit c65312b

Browse files
authored
feat: MCP optional root path env config (#18397)
1 parent db54c3f commit c65312b

File tree

3 files changed

+19
-9
lines changed

3 files changed

+19
-9
lines changed

src/AI/mcp/.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Root path prefix for MCP endpoints (e.g. /mcp makes endpoints /mcp/sse)
2+
# MCP_ROOT_PATH=/mcp
3+
14
# LLM API Keys
25
AZURE_API_KEY=your_azure_api_key_here
36
OPENAI_API_KEY=your_openai_api_key_here # OPTIONAL: Azure is used by default.

src/AI/mcp/server/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
load_dotenv()
77

8+
# MCP Path Configuration
9+
MCP_ROOT_PATH = os.getenv("MCP_ROOT_PATH", "")
10+
811
# Azure OpenAI Configuration
912
AZURE_ENDPOINT = os.getenv("AZURE_ENDPOINT", "https://rndlabaidemoss0618689180.openai.azure.com/")
1013
API_KEY = os.getenv("AZURE_API_KEY", "")

src/AI/mcp/server/main.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import argparse
1212
from contextvars import ContextVar
1313
from fastmcp import FastMCP
14+
from server.config import MCP_ROOT_PATH
1415

1516
# Context variable to track if current request is in agent mode
1617
# Set by middleware based on request path (/sse vs /agent/sse)
@@ -82,30 +83,33 @@ def main() -> None:
8283
streamable_http_path="/sse",
8384
stateless_http=True,
8485
)
85-
86+
87+
agent_mount_path = f"{MCP_ROOT_PATH}/agent"
88+
standard_mount_path = f"{MCP_ROOT_PATH}/" if MCP_ROOT_PATH else "/"
89+
8690
# Pure ASGI middleware that sets agent mode - compatible with SSE streaming
8791
class AgentModeASGIMiddleware:
8892
def __init__(self, app):
8993
self.app = app
90-
94+
9195
async def __call__(self, scope, receive, send):
9296
if scope["type"] == "http":
9397
path = scope.get("path", "")
94-
is_agent = path.startswith("/agent")
98+
is_agent = path.startswith(agent_mount_path)
9599
set_agent_mode(is_agent)
96100
return await self.app(scope, receive, send)
97-
101+
98102
# Create a new Starlette app that mounts the HTTP app at both paths.
99103
# IMPORTANT: We must propagate the FastMCP app's lifespan so that the
100104
# StreamableHTTPSessionManager task group is initialized correctly.
101105
app = Starlette(
102106
routes=[
103-
Mount('/agent', app=http_base_app), # Agent mode endpoint
104-
Mount('/', app=http_base_app), # Standard endpoint
107+
Mount(agent_mount_path, app=http_base_app), # Agent mode endpoint
108+
Mount(standard_mount_path, app=http_base_app), # Standard endpoint
105109
],
106110
lifespan=http_base_app.lifespan,
107111
)
108-
112+
109113
# Wrap with our ASGI middleware
110114
app = AgentModeASGIMiddleware(app)
111115

@@ -127,8 +131,8 @@ def custom_run(transport="sse", **kwargs):
127131
{chr(10).join(f' - {name}' for name in sorted(registered))}
128132
129133
Endpoints (Streamable HTTP):
130-
- Standard (with tracing): /sse
131-
- Agent mode (no tracing): /agent/sse
134+
- Standard (with tracing): {MCP_ROOT_PATH}/sse
135+
- Agent mode (no tracing): {MCP_ROOT_PATH}/agent/sse
132136
================================================================================
133137
""", file=sys.stderr)
134138

0 commit comments

Comments
 (0)