<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: akitana-airtanker</title>
    <description>The latest articles on Forem by akitana-airtanker (@akitana-airtanker).</description>
    <link>https://forem.com/akitana-airtanker</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3150466%2Ffb4665d4-f5a3-4e47-9890-238220901756.jpeg</url>
      <title>Forem: akitana-airtanker</title>
      <link>https://forem.com/akitana-airtanker</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/akitana-airtanker"/>
    <language>en</language>
    <item>
      <title>Python MCP Remote Server — The Dawn of the Streamable HTTP Era ~ With a Minimalist Template Featuring uv / Docker / pytest ~</title>
      <dc:creator>akitana-airtanker</dc:creator>
      <pubDate>Sun, 11 May 2025 15:21:11 +0000</pubDate>
      <link>https://forem.com/akitana-airtanker/python-mcp-remote-server-the-dawn-of-the-streamable-http-era-with-a-minimalist-template-1o6j</link>
      <guid>https://forem.com/akitana-airtanker/python-mcp-remote-server-the-dawn-of-the-streamable-http-era-with-a-minimalist-template-1o6j</guid>
      <description>&lt;h2&gt;
  
  
  First Conclusion: Python-based MCP Servers Now Run in the Cloud
&lt;/h2&gt;

&lt;p&gt;Traditionally, MCP servers, especially those implemented in Python, were often perceived as being for local use. Configurations combining Server-Sent Events (SSE) and auxiliary WebSockets frequently posed challenges for deployment in cloud environments.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;just a few days ago on May 8, 2025&lt;/strong&gt;, &lt;a href="https://github.com/modelcontextprotocol/python-sdk/releases/tag/v1.8.0" rel="noopener noreferrer"&gt;v1.8.0 of the MCP Python SDK was released&lt;/a&gt;, officially supporting the long-awaited &lt;strong&gt;Streamable HTTP transport&lt;/strong&gt;.&lt;br&gt;
The release notes proudly declare, "This is the first release supporting the new Streamable HTTP transport from protocol version 2025-03-26, which supersedes the SSE transport from protocol version 2024-11-05. 🎉", signaling a significant milestone in MCP's communication protocol.&lt;/p&gt;

&lt;p&gt;With the introduction of Streamable HTTP, bidirectional stream communication can now be handled efficiently over a single standard HTTP connection. This has significantly opened up the path for deploying and operating Python-based MCP Servers directly in common cloud environments such as VPS, Google Cloud Run, and AWS Lambda.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;By deploying to the cloud and leveraging existing HTTP infrastructure (load balancers, CDNs, WAFs, etc.), while directly calling upon Python's rich ecosystem (any machine learning libraries or LLMs) within the server, the flexibility and scalability of MCP application development using Python are dramatically improved.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  The Technical Appeal of Streamable HTTP: A Deeper Dive
&lt;/h3&gt;

&lt;p&gt;The Streamable HTTP transport in the MCP specification (see &lt;a href="https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http" rel="noopener noreferrer"&gt;official specification&lt;/a&gt;) offers a sophisticated mechanism that goes beyond simple HTTP streaming, aiming to resolve issues of the previous HTTP+SSE method. Key features include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Endpoint Consolidation and Simplified Communication&lt;/strong&gt;: Previously, separate endpoints were needed for establishing SSE connections and sending messages (e.g., &lt;code&gt;/sse&lt;/code&gt; and &lt;code&gt;/sse/messages&lt;/code&gt;). Streamable HTTP consolidates these into a single endpoint (e.g., &lt;code&gt;/mcp&lt;/code&gt;). All client messages (requests, notifications, responses) are always sent as HTTP POST requests to this single endpoint. The server then responds either with a single JSON response or by streaming the response as an SSE stream, as needed. This greatly simplifies connection management for both clients and servers.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Flexible Connection Persistence and Efficient Bidirectional Communication&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  Connections are initiated as regular HTTP requests and can be "upgraded" to an SSE stream on the same connection at the server's discretion. This eliminates the need to maintain a persistent connection at all times, improving resource efficiency, especially in serverless environments. The ability to "start with a normal HTTP connection and switch to sequential data transmission as needed, thus eliminating the need for a constantly open dedicated connection" is a significant advantage.&lt;/li&gt;
&lt;li&gt;  The server can use the established SSE stream not only to send responses to client requests but also to send notifications or additional requests to the client at any time, enabling true bidirectional communication over a single logical connection.&lt;/li&gt;
&lt;li&gt;  Clients can also establish an SSE stream via an HTTP GET request to listen for spontaneous messages from the server (e.g., resource change notifications).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Session Management and Future Robustness Enhancements (Resumability &amp;amp; Cancellability)&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  The MCP specification defines a framework for stateful session management using the &lt;code&gt;Mcp-Session-Id&lt;/code&gt; HTTP header. This allows servers to maintain client-specific state and context across multiple requests or connections.&lt;/li&gt;
&lt;li&gt;  Advanced features for more robust communication, such as stream resumption using the standard SSE &lt;code&gt;Last-Event-ID&lt;/code&gt; header (Resumability) and explicit operation cancellation by the client (Cancellability), are also included in the MCP specification. These are being progressively implemented in the SDKs and are expected to enable recovery from network interruptions and termination of unnecessary long-running processes, especially in unstable network environments.&lt;/li&gt;
&lt;li&gt;  As of MCP Python SDK v1.8.0, these advanced session management features are not yet fully implemented and are primarily considered a foundation for future extensions. However, basic Streamable HTTP send/receive operations function as specified, achieving feature parity with the previous SSE method.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Consideration for Backward Compatibility&lt;/strong&gt;: Guidelines are provided for maintaining compatibility with the older HTTP+SSE transport (protocol version 2024-11-05), allowing for a gradual transition from existing systems. For instance, Cloudflare's implementation demonstrates how a server can support both old and new clients by concurrently offering paths for the legacy SSE and the new Streamable HTTP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These characteristics allow Streamable HTTP to transcend simple unidirectional streaming, offering an efficient, flexible, and prospectively more robust bidirectional communication infrastructure over standard HTTP protocols.&lt;/p&gt;

&lt;p&gt;A Cloudflare blog post, "&lt;a href="https://blog.cloudflare.com/streamable-http-mcp-servers-python/" rel="noopener noreferrer"&gt;Bringing streamable HTTP transport and Python language support to MCP servers&lt;/a&gt;" (April 30, 2025), also emphasizes the simplicity of this new transport. While the previous SSE-based transport required managing separate endpoints for sending and receiving messages, Streamable HTTP consolidates this into a single endpoint. The article aptly describes this change: "it's like having a conversation with two phones, one for listening and one for speaking," highlighting how Streamable HTTP reduces developer burden.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Evolution of the Python SDK: Expanding Possibilities with Streamable HTTP Support
&lt;/h2&gt;

&lt;p&gt;With the MCP Python SDK now supporting Streamable HTTP, how do the options and possibilities for Python-based MCP server development expand? Let's compare it with the TypeScript SDK, which already supported Streamable HTTP, to see Python's unique advantages.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;TypeScript SDK (Node.js-based)&lt;/th&gt;
&lt;th&gt;Python SDK (v1.8.0 onwards)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Streamable HTTP Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Already supported&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Officially supported in v1.8.0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LLM &amp;amp; ML Libraries&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Relies on the JavaScript ecosystem&lt;/td&gt;
&lt;td&gt;Full utilization of Python's rich ecosystem, including PyTorch, TensorFlow, Hugging Face Transformers, etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Serverless Deployment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Proven in Cloud Functions, AWS Lambda (Node.js runtime), etc.&lt;/td&gt;
&lt;td&gt;Enables similarly easy deployment in Cloud Run, AWS Lambda (Python runtime), etc.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ecosystem Maturity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MCP support has progressed relatively early, with ample related tools and samples.&lt;/td&gt;
&lt;td&gt;Rapidly catching up by leveraging the strengths of the Python community. This template is part of that effort.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What becomes clear from this comparison is that by supporting Streamable HTTP, the Python SDK is catching up to the TypeScript SDK in terms of features, while also allowing developers to fully leverage Python's strengths in &lt;strong&gt;LLM inference and data science processing&lt;/strong&gt;. This makes tasks like the following easier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Directly executing advanced natural language processing or machine learning models within the MCP server and providing the results to clients (like AI agents) in real-time.&lt;/li&gt;
&lt;li&gt;  Seamlessly integrating existing Python-based machine learning workflows or data pipelines with MCP servers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, Python's Streamable HTTP support isn't just about enabling a new communication method; it's about opening the door to bring the entire power of Python's ecosystem 본격적으로 into the MCP world.&lt;/p&gt;
&lt;h2&gt;
  
  
  2. A Minimalist Template to Bridge the "Official Samples Gap"
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/akitana-airtanker/mcp-python-streamable-e2e-test-template" rel="noopener noreferrer"&gt;https://github.com/akitana-airtanker/mcp-python-streamable-e2e-test-template&lt;/a&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Goal&lt;/th&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Get it running quickly&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Includes &lt;code&gt;mcp-server-demo&lt;/code&gt; / &lt;code&gt;mcp-client-demo&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Eliminate environment discrepancies&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Dockerfile&lt;/code&gt; + VS Code &lt;strong&gt;Dev Container&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Start with a test-first approach&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;E2E tests with &lt;code&gt;pytest-asyncio&lt;/code&gt; included initially&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Maintain code style &amp;amp; quality&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Automated linting/formatting with &lt;code&gt;pre-commit&lt;/code&gt; + &lt;strong&gt;Ruff&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Speed up installation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Faster &lt;code&gt;venv&lt;/code&gt; and &lt;code&gt;pip&lt;/code&gt; with &lt;strong&gt;uv&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Clone the template → run &lt;code&gt;uv venv &amp;amp;&amp;amp; uv pip install -e ".[dev,test]"&lt;/code&gt; → execute &lt;code&gt;pytest&lt;/code&gt;. All within &lt;em&gt;about 3 minutes&lt;/em&gt;. You can confirm that Streamable HTTP round-trips as expected.&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Quick Start and Setup Details
&lt;/h2&gt;

&lt;p&gt;Let's dive into the setup procedure to make the most of this template and the underlying mechanisms.&lt;/p&gt;
&lt;h3&gt;
  
  
  3.1 Basic Startup Procedure
&lt;/h3&gt;

&lt;p&gt;Here's the basic flow from cloning the repository to starting the server and connecting from a client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Clone the repository&lt;/span&gt;
git clone https://github.com/akitana-airtanker/mcp-python-streamable-e2e-test-template.git my-mcp
&lt;span class="nb"&gt;cd &lt;/span&gt;my-mcp

&lt;span class="c"&gt;# 2. Create a virtual environment with uv and install dependencies&lt;/span&gt;
uv venv  &lt;span class="c"&gt;# A virtual environment will be created in the .venv directory&lt;/span&gt;
uv pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[dev,test]"&lt;/span&gt; &lt;span class="c"&gt;# Install development and test dependencies as well&lt;/span&gt;

&lt;span class="c"&gt;# 3. Activate the virtual environment&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate      &lt;span class="c"&gt;# For Linux / macOS&lt;/span&gt;
&lt;span class="c"&gt;# .venv\Scripts\activate         # For Windows (Command Prompt)&lt;/span&gt;
&lt;span class="c"&gt;# .\.venv\Scripts\Activate.ps1 # For Windows (PowerShell)&lt;/span&gt;

&lt;span class="c"&gt;# 4. Start the MCP server&lt;/span&gt;
mcp-server-demo
&lt;span class="c"&gt;# By default, it listens for requests at http://0.0.0.0:8000/mcp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open another terminal, activate the virtual environment similarly, and then run the client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# (After activating the virtual environment in another terminal)&lt;/span&gt;
&lt;span class="c"&gt;# 5. Run the MCP client&lt;/span&gt;
mcp-client-demo
&lt;span class="c"&gt;# If "Result of add(10, 5): 15" is displayed, it's successful.&lt;/span&gt;

&lt;span class="c"&gt;# 6. Run E2E tests&lt;/span&gt;
pytest
&lt;span class="c"&gt;# Confirm that all tests pass (green OK).&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.2 Key Setup Points
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;uv&lt;/code&gt; for Fast Environment Setup: Python Packaging's Next-Gen Ace
&lt;/h4&gt;

&lt;p&gt;This template fully adopts &lt;code&gt;uv&lt;/code&gt;, a new package manager for Python. It's no exaggeration to say &lt;code&gt;uv&lt;/code&gt; is one of the most注目されている (attention-grabbing) tools in the Python world right now.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;What is &lt;code&gt;uv&lt;/code&gt;?&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  Developed by &lt;strong&gt;Astral&lt;/strong&gt;, also known for the high-performance linter &lt;code&gt;Ruff&lt;/code&gt;, &lt;code&gt;uv&lt;/code&gt; is a Rust-based, high-speed Python packaging tool.&lt;/li&gt;
&lt;li&gt;  It aims not only to replace &lt;code&gt;pip&lt;/code&gt; and &lt;code&gt;venv&lt;/code&gt; but also to cover dependency locking features like &lt;code&gt;pip-tools&lt;/code&gt; and, in the future, project management functionalities similar to &lt;code&gt;Poetry&lt;/code&gt; or &lt;code&gt;PDM&lt;/code&gt; (see &lt;a href="https://www.bitecode.dev/p/a-year-of-uv-pros-cons-and-should" rel="noopener noreferrer"&gt;Bite code!'s article&lt;/a&gt; and &lt;a href="https://news.ycombinator.com/item?id=42415602" rel="noopener noreferrer"&gt;Hacker News discussion&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;  Its overwhelming speed and ambitious scope suggest it has the potential to significantly influence Python's standard toolchain (though it doesn't fully replace all features of &lt;code&gt;Poetry&lt;/code&gt; or &lt;code&gt;PDM&lt;/code&gt; at present).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Installation&lt;/strong&gt;: If &lt;code&gt;uv&lt;/code&gt; is not installed on your system, please refer to the &lt;a href="https://github.com/astral-sh/uv#installation" rel="noopener noreferrer"&gt;official uv documentation&lt;/a&gt; to install it. Methods like &lt;code&gt;pipx install uv&lt;/code&gt; or &lt;code&gt;cargo install uv&lt;/code&gt; are available.&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Benefits in this template&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;uv venv&lt;/code&gt;&lt;/strong&gt;: Virtual environment creation is literally instantaneous.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;uv pip install&lt;/code&gt;&lt;/strong&gt;: Dependency resolution and package download/installation are dramatically faster, even for projects with complex dependencies. Processes that took minutes with traditional &lt;code&gt;pip&lt;/code&gt; can often finish in seconds.&lt;/li&gt;
&lt;li&gt;  This template efficiently installs dependencies defined in &lt;code&gt;pyproject.toml&lt;/code&gt; (regular, development &lt;code&gt;[dev]&lt;/code&gt;, and test &lt;code&gt;[test]&lt;/code&gt; extras) with a single command: &lt;code&gt;uv pip install -e ".[dev,test]"&lt;/code&gt;. This speed also significantly contributes to reducing CI/CD pipeline execution times.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Adopting &lt;code&gt;uv&lt;/code&gt; reduces time costs at every stage of the development cycle, allowing you to focus more on core development tasks.&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;pre-commit&lt;/code&gt; and &lt;code&gt;Ruff&lt;/code&gt; for Quality Maintenance: Modern Python Development Best Practices
&lt;/h4&gt;

&lt;p&gt;Automatically maintaining high code quality is essential in modern software development. This template introduces this best practice by combining &lt;code&gt;pre-commit&lt;/code&gt; hooks and &lt;code&gt;Ruff&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;pre-commit&lt;/code&gt;&lt;/strong&gt;: A framework for automatically running predefined checks (hooks) before Git commits (&lt;a href="https://pre-commit.com/" rel="noopener noreferrer"&gt;official website&lt;/a&gt;).

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;pre-commit&lt;/code&gt; itself is also installed as a development dependency with &lt;code&gt;uv pip install -e ".[dev,test]"&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  To start using it, run &lt;code&gt;pre-commit install&lt;/code&gt; once in the repository root. This sets up the Git hooks, and checks will run automatically on subsequent commits.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;&lt;code&gt;Ruff&lt;/code&gt;&lt;/strong&gt;: A Rust-based, ultra-fast Python linter and formatter developed by Astral (&lt;a href="https://github.com/astral-sh/ruff" rel="noopener noreferrer"&gt;official website&lt;/a&gt;).

&lt;ul&gt;
&lt;li&gt;  What's astounding is not just its speed, but its ability to cover most of the checks and formatting previously done by multiple tools like &lt;code&gt;Flake8&lt;/code&gt;, &lt;code&gt;isort&lt;/code&gt;, &lt;code&gt;pydocstyle&lt;/code&gt;, &lt;code&gt;pyupgrade&lt;/code&gt;, etc., with &lt;code&gt;Ruff&lt;/code&gt; alone. This simplifies configuration files and significantly reduces tool management costs.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Ruff&lt;/code&gt; hooks are defined in &lt;code&gt;.pre-commit-config.yaml&lt;/code&gt;. When you try to commit, static code analysis (detecting potential bugs or deprecated practices) and formatting (unifying coding style) are automatically executed.&lt;/li&gt;
&lt;li&gt;  If issues are found, the commit is aborted, prompting you to fix them. In many cases, &lt;code&gt;Ruff&lt;/code&gt; can automatically fix the problems it finds.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This &lt;code&gt;pre-commit&lt;/code&gt; + &lt;code&gt;Ruff&lt;/code&gt; combination is rapidly becoming a de facto standard in the Python community, greatly contributing to maintaining code consistency and reducing review burden in team development.&lt;/p&gt;

&lt;h4&gt;
  
  
  VS Code Dev Container for Environment Reproducibility: A Smoother Development Experience
&lt;/h4&gt;

&lt;p&gt;If you use VS Code, the Dev Container feature can further reduce the effort of setting up your development environment and provide a smoother experience.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;What is a Dev Container?&lt;/strong&gt;: A mechanism to build a fully isolated development environment within a Docker container and use it directly from VS Code.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;How to use&lt;/strong&gt;:

&lt;ol&gt;
&lt;li&gt; Open this template project in VS Code.&lt;/li&gt;
&lt;li&gt; If the &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers" rel="noopener noreferrer"&gt;Dev Containers extension&lt;/a&gt; is installed, a notification "Reopen in Container" will appear in the bottom right. Click it.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Benefits&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  The &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; file defines everything: the Docker image to use, VS Code extensions to install, and commands to run after container creation (like &lt;code&gt;uv pip install&lt;/code&gt; and &lt;code&gt;pre-commit install&lt;/code&gt; via &lt;code&gt;postCreateCommand&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;  There's absolutely no need to install Python, &lt;code&gt;uv&lt;/code&gt;, or various tools locally.&lt;/li&gt;
&lt;li&gt;  All team members can develop with the exact same tools and versions, eliminating "it works on my machine" problems.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Peeking Inside the Template (Key File Explanations)
&lt;/h2&gt;

&lt;p&gt;This template provides the backbone for rapidly developing Streamable HTTP-enabled MCP servers. Let's look at the key files and their roles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── Dockerfile               # Container image definition (python:3.13-slim base, non-root execution)
├── .devcontainer/
│   └── devcontainer.json    # VS Code Dev Container settings
├── src/
│   └── mcp_python_streamable_e2e_test_template/
│       ├── __init__.py
│       ├── client.py        # Sample MCP client implementation
│       ├── config.py        # Configuration loading from environment variables
│       └── server.py        # FastMCP server core and tool/resource definitions
├── tests/
│   ├── conftest.py        # pytest fixtures (e.g., for starting test server)
│   └── test_client.py     # E2E test cases (tool calls via Streamable HTTP)
├── .pre-commit-config.yaml  # pre-commit hook definitions (Ruff, etc.)
├── pyproject.toml           # Project definition, dependencies (for uv)
└── README.md                # Detailed project description
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;src/server.py&lt;/code&gt; - The Heart of the MCP Server
&lt;/h3&gt;

&lt;p&gt;Defines the MCP server using &lt;code&gt;FastMCP&lt;/code&gt; and registers sample tools and resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.server.fastmcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastMCP&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;.config&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Config&lt;/span&gt;

&lt;span class="c1"&gt;# Load configuration (LOG_LEVEL, MCP_SERVER_PORT, etc. from environment variables)
&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;# ... (Port setting logic) ...
&lt;/span&gt;
&lt;span class="c1"&gt;# Create FastMCP instance (server name "Demo" is used in logs, etc.)
&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FastMCP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastMCP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Demo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log_level&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Define 'add' tool
&lt;/span&gt;&lt;span class="nd"&gt;@server.tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Add two numbers.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tool &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;add&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; called with a=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;, b=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Tool &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;add&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; result: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="c1"&gt;# Define 'greeting' resource
&lt;/span&gt;&lt;span class="nd"&gt;@server.resource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;greeting://{name}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get a personalized greeting.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Resource &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;greeting://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; accessed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello, &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="c1"&gt;# ...
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Entry point for starting the server&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MCP_TRANSPORT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;streamable-http&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Defaults to Streamable HTTP
&lt;/span&gt;    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Starting server &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; with transport &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Run the server!
&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;FastMCP("Demo")&lt;/code&gt;&lt;/strong&gt;: Creates a lightweight MCP server instance.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;@server.tool()&lt;/code&gt;&lt;/strong&gt;: Functions decorated with this are exposed as MCP tools. Type hints are used for argument and return value schema definitions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;@server.resource("greeting://{name}")&lt;/code&gt;&lt;/strong&gt;: Defines a resource matching a URI pattern. The &lt;code&gt;{name}&lt;/code&gt; part is passed as an argument to the function.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;server.run(transport="streamable-http")&lt;/code&gt;&lt;/strong&gt;: This is the command that starts the server with Streamable HTTP.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;src/client.py&lt;/code&gt; - Client to Interact with the Server
&lt;/h3&gt;

&lt;p&gt;A sample client that connects to the server using Streamable HTTP and calls a tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.client.streamable_http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;streamablehttp_client&lt;/span&gt; &lt;span class="c1"&gt;# Streamable HTTP client
&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;quiet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;server_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8000/mcp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# Target URL
&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;streamablehttp_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;as &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;client_read_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_write_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_get_session_id_callback&lt;/span&gt;
        &lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_read_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_write_stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;current_session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ClientSession&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_session&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Initialize session
&lt;/span&gt;                &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Connected. Session ID: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;client_get_session_id_callback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="n"&gt;tool_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;add&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
                &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="n"&gt;response_object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallToolResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;tool_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt; &lt;span class="c1"&gt;# Call 'add' tool
&lt;/span&gt;                &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="c1"&gt;# ... (Process response) ...
&lt;/span&gt;    &lt;span class="c1"&gt;# ... (Error handling) ...
&lt;/span&gt;
&lt;span class="c1"&gt;# ... (main function and argparse) ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;streamablehttp_client(server_url)&lt;/code&gt;&lt;/strong&gt;: An async context manager that attempts to connect to the specified URL using Streamable HTTP. On success, it returns read/write streams and a session ID callback.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;ClientSession(...)&lt;/code&gt;&lt;/strong&gt;: Manages the MCP session using the streams.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;session.call_tool(...)&lt;/code&gt;&lt;/strong&gt;: Executes the server-side tool with the given name and arguments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Dockerfile&lt;/code&gt; - Reproducible Execution Environment
&lt;/h3&gt;

&lt;p&gt;This file defines how to build a Docker image for running the MCP server application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Base image (Python 3.13 slim version)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.13-slim&lt;/span&gt;

&lt;span class="c"&gt;# ... (System utilities, uv installation) ...&lt;/span&gt;

&lt;span class="c"&gt;# Create non-root user (for security)&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; APP_USER=appuser&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;groupadd &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; useradd &lt;span class="nt"&gt;-ms&lt;/span&gt; /bin/bash &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app # Working directory&lt;/span&gt;

&lt;span class="c"&gt;# Copy dependency files &amp;amp; install with uv&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; pyproject.toml uv.lock* ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; src/ ./src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; README.md ./README.md&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;uv venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;.&lt;/span&gt; .venv/bin/activate &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    uv pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[test,dev]"&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . . # Copy remaining code&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;:&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;APP_USER&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; /app &lt;span class="c"&gt;# Change ownership&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; ${APP_USER} # Switch to non-root user&lt;/span&gt;

&lt;span class="c"&gt;# Add venv's bin directory to PATH&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; VIRTUAL_ENV="/app/.venv"&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH="/app/.venv/bin:$PATH"&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8000 # Port the server listens on&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["mcp-server-demo"] # Default command when container starts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;FROM python:3.13-slim&lt;/code&gt;&lt;/strong&gt;: Uses a lightweight official Python image as a base.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;uv venv&lt;/code&gt; &amp;amp; &lt;code&gt;uv pip install&lt;/code&gt;&lt;/strong&gt;: Sets up the environment quickly using &lt;code&gt;uv&lt;/code&gt; even inside the container.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Non-root user execution&lt;/strong&gt;: Runs processes as a non-root user (&lt;code&gt;USER ${APP_USER}&lt;/code&gt;) for better security.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;CMD ["mcp-server-demo"]&lt;/code&gt;&lt;/strong&gt;: The &lt;code&gt;mcp-server-demo&lt;/code&gt; script (the &lt;code&gt;main&lt;/code&gt; function in &lt;code&gt;src/server.py&lt;/code&gt;) is executed when the container starts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;tests/&lt;/code&gt; Directory - Quality Assurance with E2E Tests
&lt;/h3&gt;

&lt;p&gt;E2E tests using &lt;code&gt;pytest&lt;/code&gt; ensure the correctness of Streamable HTTP communication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;tests/conftest.py&lt;/code&gt; (Test Configuration and Fixtures):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;session&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mcp_server_url&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Start server on a different port (8001) for tests
&lt;/span&gt;    &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MCP_SERVER_PORT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="c1"&gt;# Specify port via environment variable
&lt;/span&gt;    &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LOG_LEVEL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WARNING&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Suppress logs during tests
&lt;/span&gt;
    &lt;span class="c1"&gt;# Start server as a background process
&lt;/span&gt;    &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Popen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mcp-server-demo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PIPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Wait for server to start (more robust checks are preferable)
&lt;/span&gt;    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://localhost:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/mcp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# Provide server URL to test cases
&lt;/span&gt;
    &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;terminate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Stop server after tests
&lt;/span&gt;    &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  The &lt;code&gt;mcp_server_url&lt;/code&gt; fixture starts &lt;code&gt;mcp-server-demo&lt;/code&gt; on &lt;strong&gt;port 8001&lt;/strong&gt; at the beginning of the session. This is because the logic in &lt;code&gt;src/server.py&lt;/code&gt; prioritizes the &lt;code&gt;MCP_SERVER_PORT&lt;/code&gt; environment variable for &lt;code&gt;FASTMCP_PORT&lt;/code&gt;. This prevents conflicts with the development server (default port 8000).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;tests/test_client.py&lt;/code&gt; (Test Cases):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.client.streamable_http&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;streamablehttp_client&lt;/span&gt;

&lt;span class="nd"&gt;@pytest.mark.asyncio&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_add_tool_success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mcp_server_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Get URL from fixture
&lt;/span&gt;    &lt;span class="n"&gt;tool_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;add&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;expected_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;streamablehttp_client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mcp_server_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;as &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="c1"&gt;# Connect to test server
&lt;/span&gt;        &lt;span class="n"&gt;read_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_session_id_callback&lt;/span&gt;
    &lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;ClientSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read_stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write_stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallToolResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isError&lt;/span&gt;
            &lt;span class="c1"&gt;# ... (Detailed result validation) ...
&lt;/span&gt;            &lt;span class="n"&gt;content_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
            &lt;span class="n"&gt;first_content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;content_list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;expected_result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  Test functions take &lt;code&gt;mcp_server_url&lt;/code&gt; as an argument and actually connect to that URL using &lt;code&gt;streamablehttp_client&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  It calls the &lt;code&gt;add&lt;/code&gt; tool and verifies that the returned result matches the expected value using &lt;code&gt;assert&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allows automatic testing of the entire flow: "When I call a tool via Streamable HTTP, I get the expected result back correctly."&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Advanced Use Cases: Deployment to the Cloud
&lt;/h2&gt;

&lt;p&gt;MCP servers created with this template are containerized, making them easy to deploy to various cloud platforms. Here are some representative examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Easy Serverless Deployment with Google Cloud Run
&lt;/h3&gt;

&lt;p&gt;Google Cloud Run is a service that allows you to deploy applications to a scalable serverless environment simply by uploading a container image.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deployment Overview&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Build the Docker image locally: &lt;code&gt;docker build -t gcr.io/YOUR_PROJECT_ID/mcp-server:latest .&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt; Push the image to Google Container Registry (GCR) or Artifact Registry: &lt;code&gt;docker push gcr.io/YOUR_PROJECT_ID/mcp-server:latest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy with the &lt;code&gt;gcloud run deploy&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud run deploy mcp-server &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--image&lt;/span&gt; gcr.io/YOUR_PROJECT_ID/mcp-server:latest &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--platform&lt;/span&gt; managed &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--region&lt;/span&gt; YOUR_REGION &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--allow-unauthenticated&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;&lt;span class="c"&gt;# Configure authentication as needed&lt;/span&gt;
    &lt;span class="nt"&gt;--port&lt;/span&gt; 8000 &lt;span class="c"&gt;# Port EXPOSEd in Dockerfile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(See also &lt;a href="https://cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-python-service" rel="noopener noreferrer"&gt;official documentation: Build and deploy a Python service&lt;/a&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Compatibility with Streamable HTTP&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Cloud Run supports HTTP/2 by default, which is technically well-suited for long-lived connections and bidirectional streaming like Streamable HTTP.&lt;/li&gt;
&lt;li&gt;  Cost-effective operation can be expected due to auto-scaling based on request volume (including scaling to zero).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Considerations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Cold start time: Can be mitigated by setting minimum instances to 1 or more.&lt;/li&gt;
&lt;li&gt;  Timeout settings: Cloud Run's request timeout (max 60 minutes) needs to be appropriately adjusted to prevent unintentional disconnection of Streamable HTTP sessions.&lt;/li&gt;
&lt;li&gt;  The Glama project's &lt;a href="https://glama.ai/mcp/servers/@the-freetech-company/mcp-sse-authenticated-cloud-run" rel="noopener noreferrer"&gt;example of deploying an authenticated SSE server to Cloud Run&lt;/a&gt; demonstrates achieving secure MCP server exposure by combining Cloud Run's IAM authentication with a local proxy.&lt;/li&gt;
&lt;li&gt;  Cloud Run has officially supported HTTP streaming (including SSE) since October 2020, so the Streamable HTTP mode of an MCP server should technically work. However, since Cloud Run's request timeout (max 15 minutes, or up to 60 minutes with configuration) might cut off very long SSE connections, MCP's recommendation (closing the stream after all responses for long-running operations are complete) and future Resumability features become important.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.2 Flexible Serverless Experience with AWS Lambda and Function URLs
&lt;/h3&gt;

&lt;p&gt;AWS Lambda also supports container images, and Function URLs allow direct HTTP endpoint exposure without an API Gateway.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deployment Overview&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Build the Docker image locally.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Push the image to Amazon Elastic Container Registry (ECR) (see &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/images-create.html" rel="noopener noreferrer"&gt;official documentation: Creating Lambda functions from container images&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create ECR repository (first time only)&lt;/span&gt;
aws ecr create-repository &lt;span class="nt"&gt;--repository-name&lt;/span&gt; mcp-server &lt;span class="nt"&gt;--image-scanning-configuration&lt;/span&gt; &lt;span class="nv"&gt;scanOnPush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="c"&gt;# Docker login&lt;/span&gt;
aws ecr get-login-password &lt;span class="nt"&gt;--region&lt;/span&gt; YOUR_REGION | docker login &lt;span class="nt"&gt;--username&lt;/span&gt; AWS &lt;span class="nt"&gt;--password-stdin&lt;/span&gt; YOUR_AWS_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com
&lt;span class="c"&gt;# Tag and push image&lt;/span&gt;
docker tag mcp-server:latest YOUR_AWS_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com/mcp-server:latest
docker push YOUR_AWS_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com/mcp-server:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3.  Create a Lambda function specifying the ECR image and enable Function URL.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ```bash
    aws lambda create-function \
        --function-name mcp-server-lambda \
        --package-type Image \
        --code ImageUri=YOUR_AWS_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com/mcp-server:latest \
        --role YOUR_LAMBDA_EXECUTION_ROLE_ARN \
        --timeout 300 \ # Adjust as needed (max 900 seconds)
        --memory-size 512 # Adjust as needed

    aws lambda create-function-url-config \
        --function-name mcp-server-lambda \
        --auth-type NONE # Or AWS_IAM
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Compatibility with Streamable HTTP&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  Function URLs support HTTP/1.1 and HTTP/2.&lt;/li&gt;
&lt;li&gt;  Lambda's execution time limit (max 15 minutes) and payload size limit (6MB for request/response) must be considered. Even with Streamable HTTP, long-duration streaming or large data transfers may require design工夫 (ingenuity/workarounds) to operate within Lambda's constraints.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Considerations&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Image Size&lt;/strong&gt;: Lambda's container image size limit is 10GB. This template's Dockerfile uses a slim image, so it usually fits, but be mindful when adding large ML libraries.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cold Starts&lt;/strong&gt;: Can be mitigated by configuring Provisioned Concurrency, but this impacts cost.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Running Heavy Models&lt;/strong&gt;: Increasing &lt;code&gt;--memory-size&lt;/code&gt; allows running larger models like PyTorch or TensorFlow, but balance this with cost.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.3 Full-Fledged Operation and Scaling with Kubernetes (K8s)
&lt;/h3&gt;

&lt;p&gt;For more advanced control and scalability, deployment to Kubernetes (K8s) is an option.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deployment Overview&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Build the Docker image and push it to any container registry (Docker Hub, GCR, ECR, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create Deployment and Service manifest files.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# deployment.yaml (excerpt)&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp-server-deployment&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# Initial replica count&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp-server&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp-server&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp-server-container&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;YOUR_REGISTRY/mcp-server:latest&lt;/span&gt; &lt;span class="c1"&gt;# Your pushed image&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="c1"&gt;# service.yaml (excerpt)&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp-server-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp-server&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt; &lt;span class="c1"&gt;# Port exposed by the Service&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8000&lt;/span&gt; &lt;span class="c1"&gt;# Container's port&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt; &lt;span class="c1"&gt;# Or ClusterIP/NodePort + Ingress&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3.  Deploy with `kubectl apply -f deployment.yaml` and `kubectl apply -f service.yaml`.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scaling and Availability&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Horizontal Pod Autoscaler (HPA)&lt;/strong&gt;: Automatically scales the number of Pods based on CPU utilization or custom metrics (see &lt;a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/" rel="noopener noreferrer"&gt;official walkthrough&lt;/a&gt;).&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# hpa.yaml (example based on CPU utilization)&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;autoscaling/v2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HorizontalPodAutoscaler&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp-server-hpa&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scaleTargetRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mcp-server-deployment&lt;/span&gt;
  &lt;span class="na"&gt;minReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;maxReplicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
  &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Resource&lt;/span&gt;
    &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cpu&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Utilization&lt;/span&gt;
        &lt;span class="na"&gt;averageUtilization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;70&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ingress&lt;/strong&gt;: Exposes the Service externally, providing routing, SSL termination, HTTP/2 support, etc. Many Ingress Controllers like Nginx Ingress Controller or Traefik support HTTP/2, which can potentially improve Streamable HTTP performance. Configuring the backend protocol in Ingress settings to &lt;code&gt;HTTP2&lt;/code&gt; (or an appropriate value like &lt;code&gt;GRPC&lt;/code&gt; supported by the controller) can help maintain HTTP/2 along the path to the Pod (check specific annotations in your Ingress Controller's documentation).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Considerations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  K8s has a steep learning curve but offers great flexibility and robustness once set up.&lt;/li&gt;
&lt;li&gt;  Managed Kubernetes services (GKE, EKS, AKS, etc.) can reduce the operational burden of the control plane.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Utilizing these cloud platforms allows you to smoothly progress through the steps of "try it out → deploy to the cloud → integrate LLM/ML" starting from this template.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Community Trends and the Future of MCP: Active Discussion and Evolution
&lt;/h2&gt;

&lt;p&gt;Since Anthropic's initial announcement (see &lt;a href="https://news.ycombinator.com/item?id=42237424" rel="noopener noreferrer"&gt;Hacker News discussion: Model Context Protocol&lt;/a&gt;, around December 2024), MCP and related technologies have been actively discussed and continue to evolve within the developer community.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;The Road to Streamable HTTP&lt;/strong&gt;: Initially, MCP was a stateful protocol assuming long-lived connections. However, the difficulty of deploying in serverless environments led to a demand for more flexible communication methods. In GitHub Discussions, particularly "&lt;a href="https://github.com/modelcontextprotocol/modelcontextprotocol/discussions/102" rel="noopener noreferrer"&gt;State, and long-lived vs. short-lived connections&lt;/a&gt;," developers from companies like Shopify and Automattic (WordPress.com) who were trying to use MCP discussed specific challenges (e.g., difficulties implementing SSE in PHP, serverless scaling issues) and proposed various solutions like session tokens, stateless/stateful protocol variants, and WebSocket usage. The current Streamable HTTP transport (HTTP POST + optional SSE) specification was adopted as a result of this active feedback loop, demonstrating MCP's evolution with the community.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Python MCP Servers on Cloudflare Workers&lt;/strong&gt;: The aforementioned Cloudflare article also introduces how to build and deploy MCP servers using Python on Cloudflare Workers. This suggests new possibilities for MCP utilization in edge computing environments. Notably, the ability to easily expose existing FastAPI applications as MCP tools using the &lt;code&gt;FastAPI-MCP&lt;/code&gt; library is welcome news for many Python developers.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Continuous Evolution of MCP Specifications and Roadmap&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  Cloudflare has indicated its policy to actively incorporate advanced features defined in the MCP specification—such as Resumability, Cancellability, and Session management—into its Agents SDK.&lt;/li&gt;
&lt;li&gt;  MCP's official roadmap prioritizes "enhancement of authentication/authorization," "service registry and discovery features," "further improvements for streaming and serverless support (including Resumability and stateless operation support)," and "enrichment of multi-language SDKs and testing." This suggests that the protocol itself is expected to continue evolving towards greater robustness and scalability. The roadmap also lists "service discovery and stateless operation support for serverless" as important items, indicating improvements conscious of environments like Cloud Run and AWS Lambda.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Expansion of the MCP Ecosystem and Industry Adoption Trends&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Entry of Major Players&lt;/strong&gt;: A noteworthy development is &lt;strong&gt;OpenAI's official announcement in March 2025 of its adoption of MCP for its products&lt;/strong&gt;. Starting with the Agents SDK, plans are in place to support MCP in ChatGPT and its APIs. CEO Sam Altman commented, "MCP has been well-received, and we are excited to add support to all our products." This fact is an extremely significant driving force for MCP to develop into an industry-standard protocol.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Support from Cloud Vendors&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Microsoft&lt;/strong&gt;: Involved with MCP from an early stage, developing the official C# SDK and implementing MCP integration in Copilot Studio and the Autogen framework. They also released an MCP server extension for Playwright (web test automation tool) and are advancing support in Azure OpenAI services and GitHub areas.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Google Cloud (including DeepMind)&lt;/strong&gt;: Announced the "MCP Toolbox for Databases" (formerly Gen AI Toolbox for Databases), supporting MCP as a standard for linking databases and AI agents. DeepMind CEO Demis Hassabis also confirmed the incorporation of MCP support into the next-generation Gemini SDK. Furthermore, Google is promoting scenarios where MCP agents run on Cloud Run, supporting it as a managed deployment target for Google's Agent2Agent (A2A) Protocol.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;AWS&lt;/strong&gt;: In April 2025, AWS open-sourced a collection of MCP servers for its AI code assistance services (presumed to be related to CodeWhisperer and CodeCatalyst). At KubeCon EU 2025, AWS also mentioned MCP support in Bedrock agents, showing its stance as a major cloud provider accepting MCP as a "bridging standard for AI and tools."&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cloudflare&lt;/strong&gt;: Promoting MCP server hosting on its Workers edge platform, announcing Python and Streamable HTTP support updates in April 2025. They provide implementations supporting both new and old transports through their Agents SDK.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Developer Tools and Startup Movements&lt;/strong&gt;: Developer tool companies like Zed, Replit, Codeium, and Sourcegraph are moving to integrate MCP into their platforms. Adoption by cloud-native startups is also active, such as Kubiya, which provides a Kubernetes-based platform, and Solo.io, which released "MCP Gateway" by extending its API gateway OSS "Kgateway."&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Abundant Server Implementations and Community Enthusiasm&lt;/strong&gt;: The MCP official website's example servers page (&lt;a href="https://modelcontextprotocol.io/examples" rel="noopener noreferrer"&gt;modelcontextprotocol.io/examples&lt;/a&gt;) lists a wide variety of official reference servers, including file system operations, DB integration, development tool integration, browser automation, communication tool integration, and AI-specific tools, demonstrating the breadth of MCP's applicability. Furthermore, leading companies like Axiom (log analysis), Browserbase (cloud browser automation), Cloudflare (developer platform), E2B (code execution sandbox), Neon (serverless Postgres), Prisma (DB management), Qdrant (vector search), Stripe (payments), Tinybird (real-time data platform), and Weaviate (Agentic RAG) are providing official MCP integrations for their platforms, accelerating ecosystem growth. The community is also actively developing and releasing MCP servers for popular tools and services like Docker container management, Kubernetes cluster operations, Linear issue tracking, Snowflake data warehouse integration, Spotify music control, and Todoist task management, showing that MCP's utility is expanding daily. The Python SDK's GitHub repository has garnered over 12,000 stars and 1,300 forks (as of May 2025), and active information exchange occurs in MCP-related Reddit communities. Reports of "hundreds of tool vendors advancing MCP integration" also indicate its high level of attention.&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Alternative Implementations and Tech Demos&lt;/strong&gt;: Movements like Blaxel developing and open-sourcing a WebSocket-based MCP implementation (a fork of Supergateway) to solve SSE challenges are also seen. Additionally, tech demo videos like "&lt;a href="https://www.youtube.com/watch?v=Ejua5LQTqek" rel="noopener noreferrer"&gt;MCP - Can Lambda do it? - Streamable HTTP Model Context Protocol&lt;/a&gt;" on the YouTube channel "the_context()" show growing interest from the tech community in combining Streamable HTTP with serverless architectures.&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Cloud Run Deployment Case Study&lt;/strong&gt;: Mark W Kiehl's Medium article "&lt;a href="https://medium.com/@markwkiehl/deploy-your-custom-mcp-ai-tool-to-cloud-run-a4d443821e67" rel="noopener noreferrer"&gt;Deploy Your Custom MCP AI Tool to Cloud Run&lt;/a&gt;" (May 1, 2025) introduces a procedure for deploying a custom MCP tool (using the &lt;code&gt;python-a2a&lt;/code&gt; library to MCP-ify a LangChain tool) to Cloud Run, serving as a reference for understanding the practicalities of operating Python MCP servers on Cloud Run (though, as it predates SDK v1.8.0, it's unclear if it directly uses Streamable HTTP).&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;MCP's Roadmap and Challenges&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;  MCP's official roadmap prioritizes "enhancement of authentication/authorization," "service registry and discovery features," "further improvements for streaming and serverless support (including Resumability and stateless operation support)," and "enrichment of multi-language SDKs and testing."&lt;/li&gt;
&lt;li&gt;  On the other hand, analyses by Gartner and others point out that "currently, there are immature aspects such as the security model, and it is mainly used for desktop application integration." The community and companies are collaboratively working to solve practical operational challenges.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Dubbed the "USB-C port of the AI industry," MCP is seeing unusually rapid adoption not only by AI pioneers like Anthropic and OpenAI but also by major cloud vendors. This powerful momentum strongly suggests MCP's great potential to grow into the de facto standard connecting AI agents and external services, and its future developments are worth watching closely.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Summary and Next Steps
&lt;/h2&gt;

&lt;p&gt;In this article, we've explained how the official support for the Streamable HTTP transport in MCP Python SDK v1.8.0 has made it easier and more flexible to operate Python-based MCP servers in cloud environments. We also introduced a minimalist, E2E-tested template to accelerate its development, touched upon key technological elements, cloud deployment examples, and active community trends.&lt;/p&gt;

&lt;p&gt;We hope this template serves as a helpful aid in your MCP server development.&lt;br&gt;
We encourage you to clone &lt;a href="https://github.com/akitana-airtanker/mcp-python-streamable-e2e-test-template" rel="noopener noreferrer"&gt;https://github.com/akitana-airtanker/mcp-python-streamable-e2e-test-template&lt;/a&gt;, first try out Streamable HTTP locally, and then expand its possibilities to the cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;MCP (Model Context Protocol) General&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  MCP Python SDK v1.8.0 Release Notes: &lt;a href="https://github.com/modelcontextprotocol/python-sdk/releases/tag/v1.8.0" rel="noopener noreferrer"&gt;https://github.com/modelcontextprotocol/python-sdk/releases/tag/v1.8.0&lt;/a&gt; (3)&lt;/li&gt;
&lt;li&gt;  FastMCP (Server within SDK): &lt;a href="https://github.com/modelcontextprotocol/python-sdk/tree/main/mcp/server/fastmcp" rel="noopener noreferrer"&gt;https://github.com/modelcontextprotocol/python-sdk/tree/main/mcp/server/fastmcp&lt;/a&gt; (27)&lt;/li&gt;
&lt;li&gt;  Model Context Protocol Official Site: &lt;a href="https://modelcontextprotocol.io/introduction" rel="noopener noreferrer"&gt;https://modelcontextprotocol.io/introduction&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  MCP Server Examples: &lt;a href="https://modelcontextprotocol.io/examples" rel="noopener noreferrer"&gt;https://modelcontextprotocol.io/examples&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Awesome MCP Servers (Community-curated list): &lt;a href="https://github.com/punkpeye/awesome-mcp-servers" rel="noopener noreferrer"&gt;https://github.com/punkpeye/awesome-mcp-servers&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Key Technologies Used in This Template&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  uv (Python Package Installer and Resolver): &lt;a href="https://github.com/astral-sh/uv" rel="noopener noreferrer"&gt;https://github.com/astral-sh/uv&lt;/a&gt; (23)&lt;/li&gt;
&lt;li&gt;  Ruff (Python linter / formatter): &lt;a href="https://github.com/astral-sh/ruff" rel="noopener noreferrer"&gt;https://github.com/astral-sh/ruff&lt;/a&gt; (21)&lt;/li&gt;
&lt;li&gt;  pre-commit (Git hook management): &lt;a href="https://pre-commit.com/" rel="noopener noreferrer"&gt;https://pre-commit.com/&lt;/a&gt; (18)&lt;/li&gt;
&lt;li&gt;  VS Code Dev Containers: &lt;a href="https://code.visualstudio.com/docs/devcontainers/containers" rel="noopener noreferrer"&gt;https://code.visualstudio.com/docs/devcontainers/containers&lt;/a&gt; (25)&lt;/li&gt;
&lt;li&gt;  pytest (Python testing framework): &lt;a href="https://docs.pytest.org/en/stable/" rel="noopener noreferrer"&gt;https://docs.pytest.org/en/stable/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  pytest-asyncio (asyncio support for pytest): &lt;a href="https://pytest-asyncio.readthedocs.io/" rel="noopener noreferrer"&gt;https://pytest-asyncio.readthedocs.io/&lt;/a&gt; (15)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;  &lt;strong&gt;Related Technologies&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;  Docker: &lt;a href="https://docs.docker.com/" rel="noopener noreferrer"&gt;https://docs.docker.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  Python &lt;code&gt;asyncio&lt;/code&gt;: &lt;a href="https://docs.python.org/3/library/asyncio.html" rel="noopener noreferrer"&gt;https://docs.python.org/3/library/asyncio.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>cloud</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
