<?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>DEV Community: Mukhtar Salim</title>
    <description>The latest articles on DEV Community by Mukhtar Salim (@geekslife).</description>
    <link>https://dev.to/geekslife</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4025075%2F9d47587f-87f4-4cdd-8741-443d35778ad3.png</url>
      <title>DEV Community: Mukhtar Salim</title>
      <link>https://dev.to/geekslife</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geekslife"/>
    <language>en</language>
    <item>
      <title>Building Production-Ready, Secure AI Backends with WebMCP and Google Cloud Run</title>
      <dc:creator>Mukhtar Salim</dc:creator>
      <pubDate>Thu, 10 Sep 2026 06:17:47 +0000</pubDate>
      <link>https://dev.to/geekslife/building-production-ready-secure-ai-backends-with-webmcp-and-google-cloud-run-5ami</link>
      <guid>https://dev.to/geekslife/building-production-ready-secure-ai-backends-with-webmcp-and-google-cloud-run-5ami</guid>
      <description>&lt;p&gt;The shift toward autonomous AI agents has exposed a critical gap in modern web infrastructure: the interface gap. For years, browser-based AI agents have had to navigate web pages the way humans do...parsing visual layouts, guessing CSS selectors, and attempting to mimic clicks.&lt;/p&gt;

&lt;p&gt;Connecting in-browser agent tools directly to modern cloud backends requires an architectural shift. By combining WebMCP on the frontend with Google Cloud Run on the backend, engineers can build a deterministic, resilient, and enterprise-grade AI foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is WebMCP?
&lt;/h2&gt;

&lt;p&gt;WebMCP (Web Model Context Protocol) is an emerging browser-level standard that allows live web pages to expose structured, machine-readable tools directly to client-side AI agents.  &lt;/p&gt;

&lt;p&gt;While Anthropic’s open-source MCP focuses on server-to-server and local-system connections (connecting LLMs to local databases, file systems, and internal enterprise services), WebMCP brings that same tooling contract into the browser DOM.  &lt;/p&gt;

&lt;p&gt;Through imperative JavaScript APIs (or declarative HTML annotations), a web application can register explicit capabilities...defining function names, JSON input schemas, and expected returns. When an AI agent visits the page, it does not need to guess what a button does; it inspects the page's registered WebMCP tools and calls them natively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does It Matter?
&lt;/h2&gt;

&lt;p&gt;Traditional web agents rely on heuristic scraping, computer vision screenshot analysis, and DOM parsing. This approach introduces major engineering bottlenecks:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Fragility:&lt;/strong&gt; A slight redesign, a changed CSS class name, or an A/B test often breaks the agent's workflow entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Token Inefficiency:&lt;/strong&gt; Feeding raw HTML or multi-resolution screenshots into LLM context windows consumes thousands of tokens per step, escalating cost and latency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Non-Determinism:&lt;/strong&gt; Vision-driven clicking frequently misfires on interactive widgets, dynamic modals, or custom calendar pickers.&lt;/p&gt;

&lt;p&gt;WebMCP establishes an explicit contract between websites and AI. Instead of asking an LLM to find an &lt;code&gt;&amp;lt;input name="search"&amp;gt;&lt;/code&gt; tag and trigger a mouse event, the page declares a search_flights tool with typed arguments. The agent interacts with the website via a reliable, typed contract, making browser automation resilient and predictable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use WebMCP Instead of a Normal API?
&lt;/h2&gt;

&lt;p&gt;WebMCP is an in-context orchestration layer for browser-agent interaction rather than a replacement for standard REST or GraphQL APIs. Unlike headless, server-to-server APIs that operate blindly and require manual state assembly and separate authentication flows, WebMCP executes inside the user's active browser session. &lt;/p&gt;

&lt;p&gt;This setup enables tools to inherit live DOM state, reuse existing login sessions, and register dynamically based on application context. Most importantly, it keeps humans in the loop by updating the UI in real time, allowing users to visibly monitor, confirm, or abort agent actions as they happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Google Cloud Run?
&lt;/h2&gt;

&lt;p&gt;Google Cloud Run is a fully managed, serverless compute platform that enables you to deploy and run containerized applications directly on top of Google’s scalable infrastructure.&lt;/p&gt;

&lt;p&gt;Cloud Run eliminates container orchestration complexity. You package your application logic...whether written in Python, Go, Node.js, or Rust...into an OCI-compliant container image, and Cloud Run provisions, executes, and scales it automatically in response to incoming HTTPS requests or asynchronous events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Features of Google Cloud Run
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;- True Serverless Scaling (Scale-to-Zero):&lt;/strong&gt; Cloud Run instances scale dynamically from zero to thousands based on incoming traffic, meaning you only pay for compute resources while requests are actively processing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Concurrency per Instance:&lt;/strong&gt; Unlike traditional Function-as-a-Service (FaaS) platforms where one instance handles one request at a time, Cloud Run allows a single container instance to process dozens of concurrent requests, optimizing memory and reducing costs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Native Secret Management:&lt;/strong&gt; Deep integration with Google Cloud Secret Manager allows API keys (such as GEMINI_API_KEY) to be injected directly as environment variables or mounted files without hardcoding credentials in container builds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Built-in Identity &amp;amp; Access Management (IAM):&lt;/strong&gt; Native support for Google Cloud IAM enables granular access policies, ensuring that only authenticated users or approved API Gateways can invoke endpoints.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Traffic Splitting &amp;amp; Canary Deployments:&lt;/strong&gt; Cloud Run allows zero-downtime rollouts and traffic splitting across multiple container revisions (e.g., routing 10% of agent traffic to a new LLM model prompt for evaluation).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- VPC Integration:&lt;/strong&gt; Containers can securely communicate with internal databases (like Cloud SQL or Memorystore) and private VPC networks without exposing resources to the public internet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros of Using Google Cloud Run for AI Backends
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;- Reduced Operational Overhead:&lt;/strong&gt; No virtual machines to patch, no Kubernetes clusters to configure, and no manual node autoscaling policies to maintain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Cost Predictability:&lt;/strong&gt; For AI workloads with unpredictable spikes or long periods of developer inactivity, scaling to zero prevents idle server bills.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Portability:&lt;/strong&gt; Because Cloud Run is standard container-based (Docker/Podman), you avoid vendor lock-in. The same container running on Cloud Run can run locally via Docker Compose or on an on-premises cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Long Request Timeouts:&lt;/strong&gt; AI workloads....especially long-form analysis, retrieval-augmented generation (RAG), and agentic reasoning loops....require longer runtimes. Cloud Run supports request timeouts up to 60 minutes, accommodating long-running generative processes without dropped connections.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Hardware Acceleration (GPU Support):&lt;/strong&gt; Cloud Run supports attached GPUs (such as NVIDIA L4s), allowing you to run self-hosted inference or embedding models serverlessly alongside lightweight orchestration APIs.7. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why Build a Production-Ready, Secure AI Backend with WebMCP and Google Cloud Run?
&lt;/h2&gt;

&lt;p&gt;While running WebMCP with a local server (localhost:8080) is ideal for developer experimentation, a production deployment presents serious enterprise requirements: session isolation, API key protection, denial-of-service resilience, and strict compliance.&lt;/p&gt;

&lt;p&gt;Pairing WebMCP and Google Cloud Run creates an optimal AI architecture for several reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A. Zero Secret Exposure on the Client&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;WebMCP runs on the user's browser, meaning client-side code is entirely public. If a browser tool attempts to call models like Google Gemini directly from JavaScript, the API key must live in the browser, exposing it to exfiltration.&lt;/p&gt;

&lt;p&gt;By having the WebMCP tool forward requests to a FastAPI container on Cloud Run, Cloud Run acts as a secure boundary. The Gemini API key remains isolated inside Google Secret Manager, never visible to the browser or network inspector.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;B. Defending Against Resource Exhaustion &amp;amp; Model Quota Draining&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because WebMCP allows autonomous or semi-autonomous tools to trigger operations, unchecked clients could inadvertently loop and consume your LLM token quotas.&lt;/p&gt;

&lt;p&gt;Placing Cloud Run behind an API Gateway or Cloud Armor allows you to implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Granular IP and token-bucket rate limiting.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Input size and schema validation (using Pydantic/FastAPI) before calling upstream models.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Token budgets and payload sanitization to mitigate prompt injection.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;C. Enterprise-Grade Session Security&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;WebMCP leverages the user’s active web session for frontend context, while Cloud Run allows you to enforce strict CORS policies and JWT/OAuth authentication. The backend verifies that the incoming request originates from your authorized frontend domain and corresponds to a validated, logged-in enterprise user before executing backend agent tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;D. Architectural Symmetry&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This architecture creates a clean separation of concerns:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- The Client (WebMCP):&lt;/strong&gt; Governs user experience, contextual state, DOM-aware interactions, and transparent human-in-the-loop controls. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- The Cloud (Cloud Run):&lt;/strong&gt; Governs compute, security boundaries, model orchestration, cost controls, and audit logging.&lt;/p&gt;

&lt;p&gt;By adopting this pattern, teams can deploy AI agents that operate reliably inside the browser without compromising enterprise security or server stability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands-On: Building the WebMCP Gemini Data Analyzer
&lt;/h2&gt;

&lt;p&gt;This practical proof-of-concept shows how an in-browser WebMCP tool registers an analytical capability, accepts parameters from an agent, and delegates execution to a containerized FastAPI service on Cloud Run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture Flow&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;index.html serves as the frontend and registers the &lt;code&gt;analyze_data_with_cloud_run&lt;/code&gt; tool via WebMCP.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The browser agent inspects the page, discovers the tool, and passes an analytical prompt with structured JSON.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The WebMCP handler sends a POST request to FastAPI's /analyze endpoint.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;FastAPI validates the payload, queries Gemini via the official SDK, and returns the response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The frontend displays the analysis live in the DOM for the user.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The application has two independent parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;index.html&lt;/code&gt; registers a WebMCP tool named &lt;code&gt;analyze_data_with_cloud_run&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A browser agent discovers and invokes that tool with a prompt and JSON data.&lt;/li&gt;
&lt;li&gt;The tool sends a &lt;code&gt;POST&lt;/code&gt; request to the FastAPI &lt;code&gt;/analyze&lt;/code&gt; endpoint.&lt;/li&gt;
&lt;li&gt;FastAPI sends the prompt and data to the Gemini API.&lt;/li&gt;
&lt;li&gt;Gemini's response is returned to the browser agent as JSON.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser agent
    |
    | WebMCP tool invocation
    v
index.html (localhost:5500)
    |
    | POST /analyze
    v
FastAPI (localhost:8080)
    |
    | Gemini generate_content
    v
Google Gemini API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Project structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── Dockerfile
├── README.md
├── index.html
├── main.py
└── requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;index.html&lt;/code&gt; contains the user interface and WebMCP tool registration.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;main.py&lt;/code&gt; contains the FastAPI application and Gemini integration.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;requirements.txt&lt;/code&gt; lists the Python dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Dockerfile&lt;/code&gt; packages the backend for container-based deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.11 or newer&lt;/li&gt;
&lt;li&gt;A Google Gemini API key&lt;/li&gt;
&lt;li&gt;Brave or Chrome with experimental WebMCP support&lt;/li&gt;
&lt;li&gt;Docker, optionally, for running the backend in a container&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Local setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Create a virtual environment
&lt;/h3&gt;

&lt;p&gt;Open a terminal in the project directory:&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="nb"&gt;cd&lt;/span&gt; /Users/mukhtarsalim/Desktop/webmcp-demo
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;venv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;venv&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\.venv\Scripts\Activate.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Install dependencies
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Configure the Gemini API key
&lt;/h3&gt;

&lt;p&gt;Create or rotate an API key in Google AI Studio. Export it only in the backend terminal:&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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'your-new-gemini-api-key'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'your-new-gemini-api-key'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not add API keys to &lt;code&gt;index.html&lt;/code&gt;, source control, screenshots, documentation, or shell scripts.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Start the backend
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvicorn main:app &lt;span class="nt"&gt;--host&lt;/span&gt; 0.0.0.0 &lt;span class="nt"&gt;--port&lt;/span&gt; 8080 &lt;span class="nt"&gt;--reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API should be available at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Health endpoint: &lt;code&gt;http://localhost:8080/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Analysis endpoint: &lt;code&gt;http://localhost:8080/analyze&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Swagger UI: &lt;code&gt;http://localhost:8080/docs&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep this terminal running.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Start the frontend
&lt;/h3&gt;

&lt;p&gt;Open a second terminal in the project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 5500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:5500&lt;/code&gt; in the WebMCP-enabled browser.&lt;/p&gt;

&lt;p&gt;Do not open &lt;code&gt;index.html&lt;/code&gt; directly with a &lt;code&gt;file://&lt;/code&gt; URL. WebMCP requires a secure context such as HTTPS or &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable WebMCP
&lt;/h2&gt;

&lt;p&gt;WebMCP is currently an experimental browser feature.&lt;/p&gt;

&lt;p&gt;For Brave:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;brave://flags/#enable-webmcp-testing&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;WebMCP for testing&lt;/strong&gt; to &lt;strong&gt;Enabled&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Restart Brave.&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;http://localhost:5500&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Open the WebMCP Tools inspector on the application tab.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For Chrome:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;code&gt;chrome://flags/#enable-webmcp-testing&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set &lt;strong&gt;WebMCP for testing&lt;/strong&gt; to &lt;strong&gt;Enabled&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Restart Chrome.&lt;/li&gt;
&lt;li&gt;Open &lt;code&gt;http://localhost:5500&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use the Model Context Tool Inspector to view and invoke the registered tool.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The tool is registered by the application page, not globally. The inspector will not find the tool while the active page is &lt;code&gt;brave://flags&lt;/code&gt;, &lt;code&gt;chrome://flags&lt;/code&gt;, or another website.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebMCP tool
&lt;/h2&gt;

&lt;p&gt;The frontend registers this tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;analyze_data_with_cloud_run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It accepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;prompt&lt;/code&gt;: the question or analysis instruction for Gemini.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;data&lt;/code&gt;: a JSON object containing the structured information to analyze.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Summarize the data and identify unusual values."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"sales"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;135&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;410&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool forwards the arguments to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST http://localhost:8080/analyze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  API usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Health check
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"online"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WebMCP Cloud Run Backend is running"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"api_key_configured"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Analyze data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;--request&lt;/span&gt; POST http://localhost:8080/analyze &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--data&lt;/span&gt; &lt;span class="s1"&gt;'{
    "prompt": "Summarize this dataset.",
    "data": {
      "value": 42,
      "category": "example"
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example successful response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Gemini-generated analysis"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the backend with Docker
&lt;/h2&gt;

&lt;p&gt;Build the image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; webmcp-demo &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--publish&lt;/span&gt; 8080:8080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'your-new-gemini-api-key'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  webmcp-demo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Docker container runs only the FastAPI backend. The frontend must still be served separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 5500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Optional Cloud Run deployment
&lt;/h2&gt;

&lt;p&gt;Cloud Run is not required for local development. It is only needed when the backend must be publicly accessible.&lt;/p&gt;

&lt;p&gt;For a hosted deployment:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build and deploy the backend container to Cloud Run.&lt;/li&gt;
&lt;li&gt;Configure &lt;code&gt;GEMINI_API_KEY&lt;/code&gt; as a Cloud Run secret or environment variable.&lt;/li&gt;
&lt;li&gt;Restrict unauthenticated access where appropriate.&lt;/li&gt;
&lt;li&gt;Configure CORS to allow only the deployed frontend origin.&lt;/li&gt;
&lt;li&gt;Replace the local backend URL in &lt;code&gt;index.html&lt;/code&gt; with the deployed HTTPS &lt;code&gt;/analyze&lt;/code&gt; URL.&lt;/li&gt;
&lt;li&gt;Serve the frontend from an HTTPS host.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do not deploy the current demo publicly without adding authentication, rate limiting, request-size limits, and restrictive CORS settings. Otherwise, third parties could consume the Gemini quota.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changes made during local setup
&lt;/h2&gt;

&lt;p&gt;The original frontend sent requests directly to a hardcoded Google Cloud Run endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://webmcp-backend-103973904738.us-central1.run.app/analyze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It was changed to the local FastAPI endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8080/analyze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removes the need to configure Cloud Run for local testing.&lt;/li&gt;
&lt;li&gt;Connects the locally served frontend to the locally running backend.&lt;/li&gt;
&lt;li&gt;Keeps Gemini API calls on the backend so the API key is not exposed to browser code.&lt;/li&gt;
&lt;li&gt;Allows the complete WebMCP flow to run on &lt;code&gt;localhost&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application was then verified with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The FastAPI health endpoint responding on port &lt;code&gt;8080&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The frontend serving successfully on port &lt;code&gt;5500&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;WebMCP for testing enabled in Brave.&lt;/li&gt;
&lt;li&gt;The tool inspector opened on the application page.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;h3&gt;
  
  
  WebMCP API not found
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Confirm the WebMCP testing flag is enabled.&lt;/li&gt;
&lt;li&gt;Restart the browser after changing the flag.&lt;/li&gt;
&lt;li&gt;Open the application through &lt;code&gt;http://localhost:5500&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Test with the latest Google Chrome if Brave does not expose the API.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  No tools registered
&lt;/h3&gt;

&lt;p&gt;The inspector must be attached to the application tab. Navigate to &lt;code&gt;http://localhost:5500&lt;/code&gt; before opening or refreshing the inspector.&lt;/p&gt;

&lt;h3&gt;
  
  
  Receiving end does not exist
&lt;/h3&gt;

&lt;p&gt;This usually means the inspector extension cannot communicate with the active page or its background process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Restart the browser.&lt;/li&gt;
&lt;li&gt;Reopen the application tab.&lt;/li&gt;
&lt;li&gt;Disable and re-enable the inspector extension.&lt;/li&gt;
&lt;li&gt;Test with current Google Chrome if the issue persists in Brave.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Backend is not reachable
&lt;/h3&gt;

&lt;p&gt;Confirm the backend process is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:8080/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also confirm that &lt;code&gt;index.html&lt;/code&gt; points to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8080/analyze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Gemini API key is not configured
&lt;/h3&gt;

&lt;p&gt;Export &lt;code&gt;GEMINI_API_KEY&lt;/code&gt; in the same terminal before starting Uvicorn. Restart Uvicorn after changing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;python main.py&lt;/code&gt; fails
&lt;/h3&gt;

&lt;p&gt;The current &lt;code&gt;main.py&lt;/code&gt; calls &lt;code&gt;uvicorn.run(...)&lt;/code&gt; without importing &lt;code&gt;uvicorn&lt;/code&gt;. Start the application with the supported command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvicorn main:app &lt;span class="nt"&gt;--host&lt;/span&gt; 0.0.0.0 &lt;span class="nt"&gt;--port&lt;/span&gt; 8080 &lt;span class="nt"&gt;--reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, add &lt;code&gt;import uvicorn&lt;/code&gt; at the top of &lt;code&gt;main.py&lt;/code&gt; before using &lt;code&gt;python main.py&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  CORS errors
&lt;/h3&gt;

&lt;p&gt;Ensure the frontend uses &lt;code&gt;http://localhost:5500&lt;/code&gt; and the backend uses &lt;code&gt;http://localhost:8080&lt;/code&gt;. For production, replace wildcard CORS configuration with the exact frontend origin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Current limitations
&lt;/h2&gt;

&lt;p&gt;This project is a proof of concept rather than a production-ready service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;/analyze&lt;/code&gt; endpoint has no authentication.&lt;/li&gt;
&lt;li&gt;CORS currently permits every origin.&lt;/li&gt;
&lt;li&gt;There is no rate limiting or request-size limit.&lt;/li&gt;
&lt;li&gt;Backend exception details may be returned to clients.&lt;/li&gt;
&lt;li&gt;Dependencies are not version-pinned.&lt;/li&gt;
&lt;li&gt;Automated tests and CI are not configured.&lt;/li&gt;
&lt;li&gt;The WebMCP tool does not yet use an &lt;code&gt;AbortSignal&lt;/code&gt; for cleanup.&lt;/li&gt;
&lt;li&gt;The WebMCP tool does not yet declare security annotations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Security notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rotate an API key immediately if it appears in terminal history, screenshots, chat, or source control.&lt;/li&gt;
&lt;li&gt;Never put &lt;code&gt;GEMINI_API_KEY&lt;/code&gt; in frontend JavaScript.&lt;/li&gt;
&lt;li&gt;Use a secret manager for hosted deployments.&lt;/li&gt;
&lt;li&gt;Add authentication and rate limiting before exposing &lt;code&gt;/analyze&lt;/code&gt; publicly.&lt;/li&gt;
&lt;li&gt;Restrict CORS to trusted frontend origins in production.&lt;/li&gt;
&lt;li&gt;Avoid returning raw provider errors to clients.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stopping the application
&lt;/h2&gt;

&lt;p&gt;Press &lt;code&gt;Ctrl+C&lt;/code&gt; in both terminals:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The terminal running Uvicorn.&lt;/li&gt;
&lt;li&gt;The terminal running the Python HTTP server.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>security</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
