<?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: Ahmad Ragab</title>
    <description>The latest articles on DEV Community by Ahmad Ragab (@asragab).</description>
    <link>https://dev.to/asragab</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%2F15452%2F0cef8d33-a7a7-475d-8f2e-96a4f19c3b5d.png</url>
      <title>DEV Community: Ahmad Ragab</title>
      <link>https://dev.to/asragab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/asragab"/>
    <language>en</language>
    <item>
      <title>Building a Model Context Protocol Server using Jina.ai and Python</title>
      <dc:creator>Ahmad Ragab</dc:creator>
      <pubDate>Fri, 03 Jan 2025 07:37:04 +0000</pubDate>
      <link>https://dev.to/asragab/building-a-model-context-protocol-server-using-jinaai-and-fastmcp-in-python-1od8</link>
      <guid>https://dev.to/asragab/building-a-model-context-protocol-server-using-jinaai-and-fastmcp-in-python-1od8</guid>
      <description>&lt;p&gt;In this post, we'll discuss the Model Context Protocol, why it might be important and walk through building an MCP Server to help us talk to &lt;a href="https://jina.ai" rel="noopener noreferrer"&gt;Jina.ai&lt;/a&gt; and be able to add web search and fact-checking functionality in Claude Desktop using Python and FastMCP.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Model Context Protocol
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://anthropic.com" rel="noopener noreferrer"&gt;Anthropic&lt;/a&gt; &lt;a href="https://www.anthropic.com/news/model-context-protocol" rel="noopener noreferrer"&gt;announced&lt;/a&gt; it around Thanksgiving last year. Although it garnered some attention, the recognition it has received may be insufficient, considering it could be a pivotal stepping stone in developing the next layer of the AI software stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  What
&lt;/h3&gt;

&lt;p&gt;The Model Context Protocol (MCP) is a standardized communication protocol designed specifically for large language models (LLMs) and other Gen AI tools. &lt;/p&gt;

&lt;p&gt;Think of it as the "HTTP of Gen AI"—just as HTTP standardized how web browsers communicate with web servers, MCP standardizes how LLM applications communicate with tools and data sources.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Do We Need MCP?
&lt;/h3&gt;

&lt;p&gt;The current landscape of LLM development faces several hurdles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tool Integration Complexity&lt;/strong&gt;: Each LLM service (like OpenAI, Anthropic, etc.) has its way of implementing tool calls and function calling, making it complex to build portable tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Context Management&lt;/strong&gt;: LLMs need access to various data sources and tools, but managing this access securely and efficiently has been challenging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Standardization&lt;/strong&gt;: Without a standard protocol, developers must rebuild integration layers for each LLM platform they want to support.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;MCP solves these challenges by providing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A standardized way to expose tools and data to LLMs&lt;/li&gt;
&lt;li&gt;A secure client-server architecture&lt;/li&gt;
&lt;li&gt;A consistent interface regardless of the underlying LLM&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How Does MCP Work?
&lt;/h3&gt;

&lt;p&gt;MCP follows a client-server architecture with three main components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;MCP Server&lt;/strong&gt;: A service that exposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tools (functions that LLMs can call)&lt;/li&gt;
&lt;li&gt;Resources (data sources)&lt;/li&gt;
&lt;li&gt;Prompts (templated instructions)&lt;/li&gt;
&lt;li&gt;Context (dynamic information)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MCP Client&lt;/strong&gt;: The application connects to MCP servers and manages communication between the LLM and the servers. Client support is in its early stages, with only a handful of tools that implement any part of the protocol specification thus far and some functionality that no clients support yet.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfqjgkjntkjny1w69eui.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfqjgkjntkjny1w69eui.png" alt="Feature Support Matrix for Clients" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And, of course, the LLM...&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;An MCP server registers its capabilities (tools, resources, etc.)&lt;/li&gt;
&lt;li&gt;A client connects to the server or launches it as a child process&lt;/li&gt;
&lt;li&gt;The LLM can then use these capabilities through a standardized interface&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Transport Protocols
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multiple transport mechanisms are supported by the protocol

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SSE&lt;/strong&gt; (Server Sent Events)

&lt;ul&gt;
&lt;li&gt;Communicates over HTTP bidirectionally, and the server process is isolated from the client&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Stdio&lt;/strong&gt; (Standard Input/Output)

&lt;ul&gt;
&lt;li&gt;Communicates over Standard Input/Output pipes, the server process is essentially a child process of the client&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;p&gt;The security situation is more nuanced. While servers using &lt;code&gt;stdio&lt;/code&gt; transport are typically colocated with the client, and thus API keys are not necessarily exposed to the internet. They do seem to get passed around fairly casually, IMO. &lt;/p&gt;

&lt;p&gt;These keys needed to be loaded into the client when the server started so they could be passed to the child process, and they even appeared in the desktop app logs, which was...concerning. &lt;/p&gt;

&lt;p&gt;The widespread use of API keys is a broader issue affecting Gen AI services, platforms, and tooling. Companies like Okta and Auth0 are working on &lt;a href="https://www.auth0.ai/" rel="noopener noreferrer"&gt;a solution&lt;/a&gt; to manage and authorize Gen AIs without exclusively relying on keys.&lt;/p&gt;

&lt;h3&gt;
  
  
  SDKs
&lt;/h3&gt;

&lt;p&gt;Anthropic officially supports low-level SDKs for &lt;a href="https://github.com/modelcontextprotocol/typescript-sdk" rel="noopener noreferrer"&gt;TypeScript&lt;/a&gt;, &lt;a href="https://github.com/modelcontextprotocol/python-sdk" rel="noopener noreferrer"&gt;Python&lt;/a&gt;, and &lt;a href="https://github.com/modelcontextprotocol/kotlin-sdk" rel="noopener noreferrer"&gt;Kotlin&lt;/a&gt;. Some of the higher-level wrappers that have recently been created already cover some of the existing boilerplate and have other nice features, such as a packaged CLI for debugging, inspecting, and installing servers on the client to make developing MCP servers easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with the Python SDK
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/modelcontextprotocol" rel="noopener noreferrer"&gt;
        modelcontextprotocol
      &lt;/a&gt; / &lt;a href="https://github.com/modelcontextprotocol/python-sdk" rel="noopener noreferrer"&gt;
        python-sdk
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      The official Python SDK for Model Context Protocol servers and clients
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;MCP Python SDK&lt;/h1&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;strong&gt;Python implementation of the Model Context Protocol (MCP)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pypi.org/project/mcp/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/e6ba71e25e692956bce8d9b0b4e043d9b7171186941670af455088139928be55/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f6d63702e737667" alt="PyPI"&gt;&lt;/a&gt;
&lt;a href="https://github.com/modelcontextprotocol/python-sdk/blob/main/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/98147347f1be2b00361083e2aac1a18781acb3109ca688b1cd1940980e9f1201/68747470733a2f2f696d672e736869656c64732e696f2f707970692f6c2f6d63702e737667" alt="MIT licensed"&gt;&lt;/a&gt;
&lt;a href="https://www.python.org/downloads/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b33b4fb36a9335985026e9b5b20cf5b1e548b7fff9f215b25abd31c9eaaa04ff/68747470733a2f2f696d672e736869656c64732e696f2f707970692f707976657273696f6e732f6d63702e737667" alt="Python Version"&gt;&lt;/a&gt;
&lt;a href="https://modelcontextprotocol.io" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/301bdc40b0f2893b417e920988f8aac322e3adab80c8a6c32657286f4aaf3a48/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f63732d6d6f64656c636f6e7465787470726f746f636f6c2e696f2d626c75652e737667" alt="Documentation"&gt;&lt;/a&gt;
&lt;a href="https://spec.modelcontextprotocol.io" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0e20327998ce56e7a24c9b61227bb10976c5c3b6188551c2bd37e357ad67e7da/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f737065632d737065632e6d6f64656c636f6e7465787470726f746f636f6c2e696f2d626c75652e737667" alt="Specification"&gt;&lt;/a&gt;
&lt;a href="https://github.com/modelcontextprotocol/python-sdk/discussions" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/587d3a9857dcc52c6f99b5109e13afc68542ab73eb8160f6a36722bd83a2cb1b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f64697363757373696f6e732f6d6f64656c636f6e7465787470726f746f636f6c2f707974686f6e2d73646b" alt="GitHub Discussions"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Table of Contents&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#overview" rel="noopener noreferrer"&gt;Overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#quickstart" rel="noopener noreferrer"&gt;Quickstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#what-is-mcp" rel="noopener noreferrer"&gt;What is MCP?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/modelcontextprotocol/python-sdk#core-concepts" rel="noopener noreferrer"&gt;Core Concepts&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#server" rel="noopener noreferrer"&gt;Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#resources" rel="noopener noreferrer"&gt;Resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#tools" rel="noopener noreferrer"&gt;Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#prompts" rel="noopener noreferrer"&gt;Prompts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#images" rel="noopener noreferrer"&gt;Images&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#context" rel="noopener noreferrer"&gt;Context&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/modelcontextprotocol/python-sdk#running-your-server" rel="noopener noreferrer"&gt;Running Your Server&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#development-mode" rel="noopener noreferrer"&gt;Development Mode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#claude-desktop-integration" rel="noopener noreferrer"&gt;Claude Desktop Integration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#direct-execution" rel="noopener noreferrer"&gt;Direct Execution&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/modelcontextprotocol/python-sdk#examples" rel="noopener noreferrer"&gt;Examples&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#echo-server" rel="noopener noreferrer"&gt;Echo Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#sqlite-explorer" rel="noopener noreferrer"&gt;SQLite Explorer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/modelcontextprotocol/python-sdk#advanced-usage" rel="noopener noreferrer"&gt;Advanced Usage&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#low-level-server" rel="noopener noreferrer"&gt;Low-Level Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#writing-mcp-clients" rel="noopener noreferrer"&gt;Writing MCP Clients&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#mcp-primitives" rel="noopener noreferrer"&gt;MCP Primitives&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#server-capabilities" rel="noopener noreferrer"&gt;Server Capabilities&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#documentation" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#contributing" rel="noopener noreferrer"&gt;Contributing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/modelcontextprotocol/python-sdk#license" rel="noopener noreferrer"&gt;License&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Overview&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This Python SDK implements the full MCP specification, making it easy to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build MCP clients that can connect to any MCP server&lt;/li&gt;
&lt;li&gt;Create MCP servers that expose resources, prompts and tools&lt;/li&gt;
&lt;li&gt;Use standard transports like stdio and SSE&lt;/li&gt;
&lt;li&gt;Handle all MCP protocol messages and lifecycle events&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;We recommend using &lt;a href="https://docs.astral.sh/uv/" rel="nofollow noopener noreferrer"&gt;uv&lt;/a&gt; to manage your Python projects:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;uv add &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;mcp[cli]&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Alternatively:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;pip install mcp&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quickstart&lt;/h2&gt;…&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/modelcontextprotocol/python-sdk" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;We'll now explore how to create an almost practical tool for reading websites, answering search queries through the web, and fact-checking information. We will be using &lt;a href="https://jina.ai" rel="noopener noreferrer"&gt;Jina.ai&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;It is a very slick service that provides a "Search Foundation platform" that combines "Embeddings, Rerankers, and Small Language Models" to aid businesses in building Gen AI and Multimodal search experiences.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;uv&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will need &lt;code&gt;uv&lt;/code&gt; installed. It is the recommended way to create and manage Python projects. It's part of a relatively recent but exciting Python toolchain called &lt;a href="https://astral.sh/" rel="noopener noreferrer"&gt;astral.sh&lt;/a&gt;. I recommend you check it out. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;uv&lt;/code&gt; aims to be a one-stop shop for managing projects, dependencies, virtual environments, versions, linting, and executing Python scripts and modules. It's written in Rust. Do with that information what you will 😏. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Claude Desktop App&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will also need to install the Claude Desktop App. For our purposes, the &lt;a href="https://claude.ai/download" rel="noopener noreferrer"&gt;Claude Desktop&lt;/a&gt; App will serve as the MCP Client and is a key target client for Anthropic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Setup
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/ASRagab" rel="noopener noreferrer"&gt;
        ASRagab
      &lt;/a&gt; / &lt;a href="https://github.com/ASRagab/mcp-jinaai-reader" rel="noopener noreferrer"&gt;
        mcp-jinaai-reader
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Model Context Protocol (MCP) Server for the Jina.ai Reader API
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;MCP Server for the Jina.ai Reader API&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;Full Walkthrough here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://dev.to/asragab/building-a-model-context-protocol-server-using-jinaai-and-fastmcp-in-python-1od8" rel="nofollow"&gt;https://dev.to/asragab/building-a-model-context-protocol-server-using-jinaai-and-fastmcp-in-python-1od8&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/ASRagab/mcp-jinaai-reader" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
 

&lt;p&gt;Using &lt;code&gt;uv&lt;/code&gt; you can initialize a project with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv init mcp-jinaai-reader &lt;span class="nt"&gt;--python&lt;/span&gt; 3.11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a folder called &lt;code&gt;mcp-jinaai-reader&lt;/code&gt; and a &lt;code&gt;.python-version&lt;/code&gt; along with a &lt;code&gt;pyproject.toml&lt;/code&gt;.&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;mcp-jinaai-reader
uv venv 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a virtual env corresponding to the python version we chose.  &lt;/p&gt;

&lt;p&gt;After creating the environment, it will provide instructions on how to activate it for the session.&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;source&lt;/span&gt; .venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a &lt;code&gt;src&lt;/code&gt; directory and install the one dependency we need&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uv add &lt;span class="s2"&gt;"mcp[cli]"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file at the project root and add your &lt;code&gt;JINAAI_API_KEY&lt;/code&gt; to the file. You can obtain one for free by signing up at &lt;a href="http://jina.ai" rel="noopener noreferrer"&gt;Jina&lt;/a&gt;. Generally, any API keys or other env variables your server needs to run will go in this file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JINAAI_API_KEY=jina_*************
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;src&lt;/code&gt; directory, create a &lt;code&gt;server.py&lt;/code&gt; file...and you should be ready to code. &lt;/p&gt;

&lt;h3&gt;
  
  
  Server Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&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;import&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;urllib.parse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urlparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Starting with the imports: &lt;code&gt;httpx&lt;/code&gt;, will be the library we use here to make http requests. The &lt;code&gt;urlparse&lt;/code&gt; method helps us determine whether a string is possibly a valid URL.&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="c1"&gt;# Initialize the MCP server 
&lt;/span&gt;&lt;span class="n"&gt;mcp&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;search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dependencies&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;mcp[cli]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This initializes the server; the first argument is the tool's name. There's a &lt;a href="https://github.com/modelcontextprotocol/python-sdk/issues/148" rel="noopener noreferrer"&gt;bug&lt;/a&gt; that requires adding the &lt;code&gt;mcp[cli]&lt;/code&gt; as a dependency; this shouldn't be necessary but will likely be fixed shortly.&lt;/p&gt;

&lt;p&gt;If you have other dependencies, you must add them here so the client knows you need to install them before running the client; we will see how that works in a moment.&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="c1"&gt;# Configuration
&lt;/span&gt;&lt;span class="n"&gt;JINAAI_SEARCH_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://s.jina.ai/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;JINAAI_READER_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://r.jina.ai/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;JINAAI_GROUNDING_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://g.jina.ai/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;JINAAI_API_KEY&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;JINAAI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can probably suss out the pattern here, but Jina uses different subdomains to route particular requests. The search endpoint expects a query, the reader endpoint expects a URL, and the grounding endpoint can provide the llm with a specific response or answer. &lt;/p&gt;

&lt;p&gt;Grounding is a much larger topic and is used with other techniques, such as RAG and fine-tuning, to assist LLMs in reducing hallucinations and improving decision-making.&lt;/p&gt;

&lt;h3&gt;
  
  
  Our first tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@mcp.tool&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;def&lt;/span&gt; &lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_or_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="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;
  Read content from a URL or perform a search query.
  &lt;/span&gt;&lt;span class="sh"&gt;"""&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;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;JINAAI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;JINAAI_API_KEY environment variable is not set&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;headers&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;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&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;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;JINAAI_API_KEY&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-Retain-Images&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;none&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;X-Timeout&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;20&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;X-Locale&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;en-US&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&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;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;is_valid_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_or_url&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-With-Links-Summary&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;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;url&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;JINAAI_READER_URL&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;query_or_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;url&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;JINAAI_SEARCH_URL&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;query_or_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
      &lt;span class="n"&gt;response&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;
  &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The annotation &lt;code&gt;@mcp.tool&lt;/code&gt; does a lot of the heavy lifting. Similar annotations for resources and prompts exist in the library. The annotation extracts the details of the function signature and return type to create an input and output schema for the llm to call the tool. It configures the tool so the client understands the server's capabilities. It also registers the function calls as handlers for the configured tool. &lt;/p&gt;

&lt;p&gt;Next, you'll notice that the function is &lt;code&gt;async&lt;/code&gt;. No runtime configuration is needed, and no &lt;code&gt;asyncio.run&lt;/code&gt; stuff either. If you need to, for some reason, run the server as a standalone service, you do need to handle some of this yourself. There is an example in the FastMCP repo for how to do this.&lt;/p&gt;

&lt;p&gt;The function body is reasonably uninteresting; it validates whether it is receiving a URL, sets the appropriate headers, calls the Jina endpoint, and returns the text.&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_valid_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;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="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
  Validate if the given string is a proper URL.
  &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
  &lt;span class="k"&gt;try&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="nf"&gt;urlparse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scheme&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http&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;https&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="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;netloc&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
  &lt;span class="k"&gt;except&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the rather simple function for determining the validity of a possible url string.&lt;/p&gt;

&lt;h3&gt;
  
  
  Second Tool
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@mcp.tool&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;def&lt;/span&gt; &lt;span class="nf"&gt;fact_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&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;
  Perform a fact-checking query.
  &lt;/span&gt;&lt;span class="sh"&gt;"""&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;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;JINAAI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;JINAAI_API_KEY environment variable is not set&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

      &lt;span class="n"&gt;headers&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;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&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;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;JINAAI_API_KEY&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Accept&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;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&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="n"&gt;httpx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;AsyncClient&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;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;url&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;JINAAI_GROUNDING_URL&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;response&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;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;res&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="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&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="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to fetch fact-check result&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&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;reason&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it...&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing and Debugging
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mcp dev src/server.py &lt;span class="nt"&gt;--with-editable&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the above command will start the mcp inspector. It's a tool that the sdk provides in order to test and debug server responses. The &lt;code&gt;--with-editable&lt;/code&gt; flag allows you to make changes to the server without having to relaunch the inspector (highly, HIGHLY recommended).&lt;/p&gt;

&lt;p&gt;You should see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;🔍 MCP Inspector is up and running at http://localhost:5173 🚀
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default the inspector runs on port 5173, and the server (the code you just wrote) will run on port 3000, you can change this by setting the &lt;code&gt;SERVER_PORT&lt;/code&gt; and &lt;code&gt;CLIENT_PORT&lt;/code&gt; before invocation.&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="nv"&gt;SERVER_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3000 mcp dev src/server.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Inspector
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbl1qwj887ambqhv1826j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbl1qwj887ambqhv1826j.png" alt="Screenshot of the inspector tool" width="800" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If all goes well you should see something like the above, on the left you can add the environment variables you'll need, here the &lt;code&gt;JINAAI_API_KEY&lt;/code&gt; is the only one. &lt;/p&gt;

&lt;p&gt;If you click on &lt;code&gt;Tools&lt;/code&gt; on the top menu bar, and then &lt;code&gt;List Tools&lt;/code&gt; you should see the tools we created, notice that the docstring serves as the description for the tool.&lt;/p&gt;

&lt;p&gt;Clicking on a particular tool will bring up the textboxes for you to enter the parameters needed to call the tool. &lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the Server
&lt;/h2&gt;

&lt;p&gt;After you are satisfied things are working as expected, you are now ready to install the server on the Claude Desktop App client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mcp &lt;span class="nb"&gt;install &lt;/span&gt;src/server.py &lt;span class="nt"&gt;-f&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am sure in the future it will support other clients, but for now, this is all you need to do. The &lt;code&gt;-f .env&lt;/code&gt; will pass the env variables to the app client.&lt;/p&gt;

&lt;p&gt;What this does under the hood is update the &lt;code&gt;claude_desktop_config.json&lt;/code&gt; and provides the necessary command and arguments to run the server. By default this uses &lt;code&gt;uv&lt;/code&gt; which must be available on your &lt;code&gt;PATH&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If you now open the Claude Desktop App, and go to the Menu Bar and Click &lt;code&gt;Claude &amp;gt; Settings&lt;/code&gt; and then click on &lt;code&gt;Developer&lt;/code&gt; you should see the name of your tool you set when initializing the server. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F83pohvvztgwb7dlik6oz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F83pohvvztgwb7dlik6oz.png" alt="Screenshot of Claude Desktop App Settings" width="775" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on it should bring up it's config. Not only will you know how it gets executed, but in the &lt;code&gt;Advanced Options&lt;/code&gt; you'll see the env variables that have been set 😬.&lt;/p&gt;

&lt;p&gt;You can also edit this config directly, but I wouldn't necessarily recommend it here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Profit
&lt;/h2&gt;

&lt;p&gt;If all goes well when you go the Desktop App you should see no errors (if you do, going to the &lt;code&gt;Settings&lt;/code&gt; should give you a button to check out the logs and investigate from there). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhu34f6y1htgg4v168vg0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhu34f6y1htgg4v168vg0.png" alt="Chat Window with Hammer Symbol" width="723" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally you should see a hammer symbol with the number of individual tools you have at your disposal (note: your count should be 2 unless you've installed other MCP servers)&lt;/p&gt;

&lt;p&gt;Rather than invoking the tool directly you chat with the app as you would normally, and when it encounters a situation where it decides that the tool is helpful it will ask if you want to use it. No additional code or configuration here is necessary. &lt;/p&gt;

&lt;p&gt;I think it relies both on the tool name and description in order to decide whether it is appropriate, so it's worth crafting a clear simple description of what the tool does.&lt;/p&gt;

&lt;p&gt;You will get a prompt like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxkb0h7mntkp6xsd78s7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxkb0h7mntkp6xsd78s7x.png" alt="Prompt for tool" width="797" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you can just "chat" with it, admittedly the tool as written sometimes runs into issues. Occasionally it decides it can't access the internet, sometimes it fails to retrieve results, but sometimes you get this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3adxcmp1mm2ec41jynkf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3adxcmp1mm2ec41jynkf.png" alt="Chatting Using Tool" width="800" height="1726"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This had kind of a natural flow, where it read the page, provided a summary, and you ask it to go to a specific article and read that. &lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;Hopefully, that gave you some insight into MCP Servers. There's plenty to read and watch but one more site I'll recommend is &lt;a href="https://glama.ai/mcp/servers?attributes=" rel="noopener noreferrer"&gt;glama.ai&lt;/a&gt;. They maintain a fairly comprehensive list of available MCP Servers to download and try out, including other web search tools that are more reliable than our toy example. Check it out, and thank you for following along.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>python</category>
      <category>jinaai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Scopes, Closures, Loops in ES5/ES6: An Incomplete Catalog of Approaches</title>
      <dc:creator>Ahmad Ragab</dc:creator>
      <pubDate>Sun, 19 Apr 2020 23:29:22 +0000</pubDate>
      <link>https://dev.to/asragab/scopes-closures-loops-in-es5-es6-an-incomplete-catalog-of-approaches-28p</link>
      <guid>https://dev.to/asragab/scopes-closures-loops-in-es5-es6-an-incomplete-catalog-of-approaches-28p</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;The classic problem is that closures (or as I like to think of them "captures") in javascript close over their environment, but that environment is lexically scoped, and not as the braces might easily convince you otherwise, block scoped. Thus, even though &lt;code&gt;var text&lt;/code&gt; and &lt;code&gt;var i&lt;/code&gt; are declared with the &lt;code&gt;for-loop&lt;/code&gt; they are available in the entirety of the function's scope. This also means that their mutations (vars are mutable) are visible to all parts of the function. &lt;/p&gt;

&lt;p&gt;Here we are iterating through a loop 10 ten times, and each time we are pushing into the &lt;code&gt;storedClosures&lt;/code&gt; array, a function that console logs the value of &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt;, later we call the environment, and foreach function in the &lt;code&gt;storedClosures&lt;/code&gt; array we call that function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;storedClosures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`text from env: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="nx"&gt;storedClosures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// last valid value in the loop is 9, when closure is called i is now 10&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | inside closure &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;storedClosures&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Broken closure:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The surprising result for the uninitiated, is the output looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Broken closure:
text from env: 9 | inside closure 10
text from env: 9 | inside closure 10
text from env: 9 | inside closure 10
text from env: 9 | inside closure 10
text from env: 9 | inside closure 10
text from env: 9 | inside closure 10
text from env: 9 | inside closure 10
text from env: 9 | inside closure 10
text from env: 9 | inside closure 10
text from env: 9 | inside closure 10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because the variable &lt;code&gt;i&lt;/code&gt; has the value it has when the scope is finished, which is 10, but the reason the first number is nine and the second is 10, is that the last value &lt;code&gt;i&lt;/code&gt; had inside the loop is 9 and only later when the function is called does it close on the value of &lt;code&gt;i&lt;/code&gt; after the loop completed. Confusing, right?&lt;/p&gt;




&lt;p&gt;We will now review a few common workarounds to this problem, the first three in ES5, and next being the ES6+ solution&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix 1: In Darkness &lt;code&gt;.bind()&lt;/code&gt; Them
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Solution 1 (Pre-ES6): create function to close over outside the environment&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;closureFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | inside closure &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;environmentWithBoundClosure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;storedClosures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`text from env: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="c1"&gt;// use bind to return new function, with text, i closed over each time during the loop&lt;/span&gt;
    &lt;span class="nx"&gt;storedClosures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;closureFunc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;storedClosures&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;Solution 1 | Using bound closure separately defined (ES5):&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;environmentWithBoundClosure&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We define a separate function called &lt;code&gt;closureFunc&lt;/code&gt; and then inside the loop we call the magical &lt;code&gt;.bind()&lt;/code&gt; of which much has been &lt;a href="https://www.smashingmagazine.com/2014/01/understanding-javascript-function-prototype-bind/" rel="noopener noreferrer"&gt;written&lt;/a&gt; about, what happens here is a &lt;em&gt;new&lt;/em&gt; function is returned by the bind call, with the &lt;code&gt;this&lt;/code&gt; variable and arguments modified as necessary. Here, we simply provide the current value of &lt;code&gt;text&lt;/code&gt; and &lt;code&gt;i&lt;/code&gt; for the new function to close over.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Solution 1 | Using bound closure separately defined (ES5):
text from env: 0 | inside closure 0
text from env: 1 | inside closure 1
text from env: 2 | inside closure 2
text from env: 3 | inside closure 3
text from env: 4 | inside closure 4
text from env: 5 | inside closure 5
text from env: 6 | inside closure 6
text from env: 7 | inside closure 7
text from env: 8 | inside closure 8
text from env: 9 | inside closure 9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fixed, yeah! Note here as well that the value of &lt;code&gt;i&lt;/code&gt; in the &lt;code&gt;text&lt;/code&gt; from the "env" as well as inside the closure are aligned, since we don't close over the value of &lt;code&gt;i&lt;/code&gt; anymore outside the for-loop itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix 2: Double your closures, double your funcs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Solution 2 (Pre-ES6): create doubly nested IIFE and call with i&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;environmentWithDoublyNestedClosure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;storedClosures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`text from env: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="nx"&gt;storedClosures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | inside closure &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// IIFE is invoked with the current values of text and i&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;storedClosures&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;Solution 2 | Using nested closure with IIFE (ES5):&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;environmentWithDoublyNestedClosure&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This workaround makes use of an &lt;a href="https://blog.cloudboost.io/understanding-immediately-invoked-function-expression-iife-c08c49b2e7c1" rel="noopener noreferrer"&gt;IIFE (Immediately Invoked Function Expression)&lt;/a&gt;, what this does is allows you define a function, and then immediate call it the syntax is a little busy but is something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/*do stuff*/&lt;/span&gt; &lt;span class="p"&gt;})(&lt;/span&gt;&lt;span class="nx"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;arg2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So while we are immediately invoking our function, what we are getting back for our invocation is yet another function. That function or closure has closed over the arguments that were provided during the invocation, the current values of &lt;code&gt;text&lt;/code&gt; and &lt;code&gt;i&lt;/code&gt;. We get the same fixed results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix 3: &lt;code&gt;forEach&lt;/code&gt; FTW
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Solution 3 (Pre-ES6): use forEach to manage iteration&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;environmentWithForEach&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;storedClosures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;range&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;length&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="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Function&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// ugly range hack&lt;/span&gt;
  &lt;span class="nx"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;storedClosures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`text from env: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | inside closure &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;storedClosures&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;Solution 3 | Using ForEach (ES5):&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;environmentWithForEach&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can ignore the &lt;a href="https://github.com/gromgit/jstips-xe/blob/master/tips/33.md" rel="noopener noreferrer"&gt;ugly range hack&lt;/a&gt;, I just wanted some way to generate a list of integers using a range (why this wizardry is required is beyond me). Just imagine you have some other array that you are looping through in order to generate the closures. The real trick is that &lt;code&gt;.forEach()&lt;/code&gt; graciously creates a local environment for us to close over every iteration, meaning the &lt;code&gt;i&lt;/code&gt; in the range is lexically scoped to the bounds of the &lt;code&gt;forEach&lt;/code&gt; call.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fix 4: &lt;code&gt;let&lt;/code&gt; the sunshine in
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//Solution 4 (ES 6+): Use let&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;environmentWithLet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;storedClosures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="c1"&gt;//let is required for iteration variable i and the text which creates a block level scope to close over&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`text from env: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="nx"&gt;storedClosures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | inside closure &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;storedClosures&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;Solution 4 | Using Let (ES6+):&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;environmentWithLet&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;func&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;func&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply changing the &lt;code&gt;var&lt;/code&gt;s to &lt;code&gt;let&lt;/code&gt;s for the &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;text&lt;/code&gt; variables changes the scope of the variable to be at the block level, thus they are closed over each time through the iteration - providing the proper results again.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>scope</category>
      <category>closures</category>
    </item>
  </channel>
</rss>
