.NET Aspire isn’t limited to .NET microservices — you can orchestrate Python components just as easily.
In this post, we’ll look at how to run a Python MCP (Model Context Protocol) server inside an Aspire application, integrate it with the MCP Inspector, and expose it via a Dev Tunnel for testing.
Folder Layout
05_PythonMCP/
├─ AppHost.cs
├─ PythonMCP.csproj
├─ appsettings.json
├─ appsettings.Development.json
├─ NuGet.config
├─ README.md
└─ pymcp/
├─ main.py
├─ requirements.txt
└─ (optional) .venv/
AppHost.cs
Here’s the full orchestration file:
var builder = DistributedApplication.CreateBuilder(args);
var inspector = builder.AddMcpInspector("mcp-inspector");
var tunnel = builder.AddDevTunnel("dev-tunnel");
var pyMcpServer = builder.AddPythonApp(
name: "pymcp",
appDirectory: "./pymcp",
scriptPath: "main.py"
).WithHttpEndpoint(env: "PORT");
tunnel.WithReference(pyMcpServer, allowAnonymous: true);
inspector.WithMcpServer(pyMcpServer);
builder. Build().Run();
What this does
AddMcpInspector("mcp-inspector")
Adds the MCP Inspector — a visual client to inspect and test MCP servers.AddDevTunnel("dev-tunnel")
Creates a local tunnel to expose the Python MCP endpoint externally.AddPythonApp("pymcp", "./pymcp", "main.py")
Registers your Python app as an Aspire component.
It will executepython main.pyin thepymcpfolder..WithHttpEndpoint(env: "PORT")
Instructs Aspire to provide a dynamic HTTP port to the app via thePORTenvironment variable.tunnel.WithReference(pyMcpServer, allowAnonymous: true)
Allows access to the MCP server through the Dev Tunnel.inspector.WithMcpServer(pyMcpServer)
Connects the MCP Inspector to your running Python MCP app.
Python MCP Server
pymcp/main.py
import os
from mcp.server.fastmcp import FastMCP
PORT = int(os.environ.get("PORT", "8000"))
mcp = FastMCP(
name="PyMCP",
host="0.0.0.0",
port=PORT,
stateless_http=True, # optional
# streamable_http_path="/" # optional: expose at "/" instead of "/mcp"
)
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
@mcp.resource("status://ping")
def ping() -> str:
return "ok"
if __name__ == "__main__":
mcp.run(transport="streamable-http")
Key concepts
- Tools → functions that can be invoked by clients or AI agents.
Example:add(a, b)above. - Resources → data endpoints or read-only assets.
Example:"status://ping"returns"ok". - Prompts → (optional) reusable instructions or templates for AI agents.
With FastMCP, everything is automatically exposed over HTTP and ready to integrate with MCP clients like the Inspector or external LLM agents.
Setting up the Python environment
From inside the pymcp directory:
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
deactivate
This ensures the FastMCP runtime is available locally.
When Aspire launches the app, it will use the default Python interpreter in your system (or one defined in the environment).
Run the whole setup
From the root of the project (05_PythonMCP):
dotnet run
Aspire will:
- Start the MCP Inspector.
- Start the Dev Tunnel.
- Launch your Python MCP app.
Open the Aspire dashboard — you’ll see all three components:
pymcp(the FastMCP server)mcp-inspectordev-tunnel
Click on the Inspector to explore your tools and resources interactively.
How It Works Together
- Aspire orchestrates everything — all services share the same lifecycle.
- The Python app runs as a first-class citizen under Aspire.
- The Inspector automatically connects to your Python MCP endpoint via the tunnel.
- You can test, monitor, and extend everything without switching environments.
Extending the Example
Want to go further?
- Add new
@mcp.tool()functions for your own logic (e.g. database access, file readers, or AI calls). - Define a
@mcp.prompt()to register reusable AI instructions. - Connect the MCP Inspector to other MCP servers or clients.
- Replace the Dev Tunnel with a YARP reverse proxy or a public HTTPS endpoint.
This small sample shows that Aspire can orchestrate Python MCP servers just like any .NET component.
You get unified logs, health checks, dashboards, and service wiring — with Python running seamlessly next to your C# code.
That’s all folks!
Cheers!
Gašper Rupnik
{End.}

Leave a comment