


Building a Model Context Protocol Server using Jina.ai and FastMCP in Python
Jan 05, 2025 am 07:25 AMIn 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 Jina.ai and be able to add web search and fact-checking functionality in Claude Desktop using Python and FastMCP.
The Model Context Protocol
Anthropic announced 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.
What
The Model Context Protocol (MCP) is a standardized communication protocol designed specifically for large language models (LLMs).
Think of it as the "HTTP of AI"—just as HTTP standardized how web browsers communicate with web servers, MCP standardizes how LLM applications communicate with tools and data sources.
Why Do We Need MCP?
The current landscape of LLM development faces several hurdles:
Tool Integration Complexity: Each LLM service (like OpenAI, Anthropic, etc.) has its way of implementing tool calls and function calling, making it complex to build portable tools.
Context Management: LLMs need access to various data sources and tools, but managing this access securely and efficiently has been challenging.
Standardization: Without a standard protocol, developers must rebuild integration layers for each LLM platform they want to support.
MCP solves these challenges by providing:
- A standardized way to expose tools and data to LLMs
- A secure client-server architecture
- A consistent interface regardless of the underlying LLM
How Does MCP Work?
MCP follows a client-server architecture with three main components:
-
MCP Server: A service that exposes:
- Tools (functions that LLMs can call)
- Resources (data sources)
- Prompts (templated instructions)
- Context (dynamic information)
MCP Client: 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.
And, of course, the LLM...
The workflow is straightforward:
- An MCP server registers its capabilities (tools, resources, etc.)
- A client connects to the server
- The LLM can then use these capabilities through a standardized interface
Transport Protocol
- Multiple Transport Mechanisms
- SSE (Server Sent Events)
- Communicates over HTTP bidirectionally, server process is isolated from client
- Stdio (Standard Input/Output)
- Communicates over Standard Input/Output pipes, server process is essentially a child process of the client
- SSE (Server Sent Events)
Security
The security situation is more nuanced. While servers using stdio 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.
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.
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 a solution to manage and authorize Gen AIs without relying on keys.
SDKs
Anthropic officially supports low-level SDKs for TypeScript, Python, and Kotlin. Some of the boilerplate wrappers that have recently been created already cover some of the boilerplate and have other nice features, such as a CLI for debugging, inspecting, and installing servers on the client to make developing MCP servers easier.
Getting Started with FastMCP
jlowin
/
fastmcp
The fast, Pythonic way to build Model Context Protocol servers ?
FastMCP ?
The fast, Pythonic way to build MCP servers.
Model Context Protocol (MCP) servers are a new, standardized way to provide context and tools to your LLMs, and FastMCP makes building MCP servers simple and intuitive. Create tools, expose resources, and define prompts with clean, Pythonic code:
# demo.py from fastmcp import FastMCP mcp = FastMCP("Demo ?") @<span>mcp.tool()</span> def add(a: int, b: int) -> int: """Add two numbers""" return a + b
That's it! Give Claude access to the server by running:
fastmcp install demo.py
FastMCP handles all the complex protocol details and server management, so you can focus on building great tools. It's designed to be high-level and Pythonic - in most cases, decorating a function is all you need.
Key features:
- Fast: High-level interface means less code and faster development
- Simple…
FastMCP is one such framework. 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 Jina.ai.
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.
Prerequisites
- uv
You will need uv installed. It is the recommended way to create and manage Python projects. It's part of a relatively recent but exciting Python toolchain called astral.sh. I recommend you check it out.
It 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 ?.
- Claude Desktop App
You will also need to install the Claude Desktop App. For our purposes, the Claude Desktop App will serve as the MCP Client and is a key target Client for Anthropic.
ASRagab
/
mcp-jinaai-reader
Model Context Protocol (MCP) Server for the Jina.ai Reader API
MCP Server for the Jina.ai Reader API
Full Walkthrough here:
https://dev.to/asragab/building-a-model-context-protocol-server-using-jinaai-and-fastmcp-in-python-1od8
Project Setup
Using uv you can initialize a project with:
# demo.py from fastmcp import FastMCP mcp = FastMCP("Demo ?") @<span>mcp.tool()</span> def add(a: int, b: int) -> int: """Add two numbers""" return a + b
This will create a folder called mcp-jinaai-reader and a .python-version along with a pyproject.toml.
fastmcp install demo.py
This will create a virtual env corresponding to the python version we chose.
After creating the environment, it will provide instructions on how to activate it for the session.
uv init mcp-jinaai-reader --python 3.11
Add a src directory and install the one dependency we need
cd mcp-jinaai-reader uv venv
Create a .env file at the project root and add your JINAAI_API_KEY to the file. You can obtain one for free by signing up at Jina. In general, any API keys or other env variables your server needs to run will go in this file.
source .venv/bin/activate
In the src directory, create a server.py file...and we should be able to get to the code.
Server Code
uv add fastmcp
Starting with the imports: httpx, will be the library we use here to make http requests; we need the urlparse method to help us determine whether a string is possibly a valid URL.
JINAAI_API_KEY=jina_*************
This initializes the server; the first argument is the tool's name. I am not 100% sure why uvicorn needs to be explicitly added as a dependency here since it is a transitive dependency of FastMCP but it does seem to be required.
It is likely due to how the fastmcp cli (more on that shortly) installs the server. 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.
from fastmcp import FastMCP import httpx from urllib.parse import urlparse import os
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.
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.
Our first tool
# Initialize the MCP server mcp = FastMCP("search", dependencies=["uvicorn"])
The annotation @mcp.tool 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.
Next, you'll notice that the function is async. No runtime configuration is needed, and no asyncio.run 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.
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.
# demo.py from fastmcp import FastMCP mcp = FastMCP("Demo ?") @<span>mcp.tool()</span> def add(a: int, b: int) -> int: """Add two numbers""" return a + b
Second Tool
fastmcp install demo.py
And that's it...
Testing and Debugging
uv init mcp-jinaai-reader --python 3.11
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 --with-editable flag allows you to make changes to the server, without having to relaunch the inspector (highly, HIGHLY recommended)
You should see:
cd mcp-jinaai-reader uv venv
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 SERVER_PORT and CLIENT_PORT before invocation.
source .venv/bin/activate
The Inspector
If all goes well you should see something like the following, on the left you can add the environment variables you'll need, here the JINAAI_API_KEY is the only one.
If you click on Tools on the top menu bar, and then List Tools you should the tools we created, notice that the docstring serves as the description for the tool.
Clicking on a particular tool will bring up the textboxes for you to enter the parameters needed to call the tool.
Installing the Server
After you are satisfied things are working as expected, you are now ready to install the server on the Claude Desktop App client.
uv add fastmcp
Will do this, I am sure in the future it will support other clients, but for now, this is all you need to do. The -f .env will pass the env variables to the app client.
What this does under the hood is update the claude_desktop_config.json and provides the necessary command and arguments to run the server. By default this uses uv which must be available on your PATH.
If you now open the Claude Desktop App, and go to the Menu Bar and Click Claude > Settings and then click on Developer you should see the name of your tool you set when initializing the server.
Clicking on it should bring up it's config. Not only will you how it gets executed, but in the Advanced Options you'll see the env variables that have been set.
You can also edit this config directly, but I wouldn't necessarily recommend it here.
Running it
If all goes well when you go the Desktop App you should see no errors (if you do, going to the Settings should give you a button to check out the logs and investigate from there).
Additionally you should see a hammer symbol with the number of individual tools you have at your disposal (note: yours should probably be two unless you've installed other MCP servers)
Rather than invoking the tool directly you chat with the app as you would normally, and when it encounters a situation where it deduces that the tool is helpful it will ask if you want to use it. No additional code or configuration here is necessary.
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.
You will get a prompt like the following:
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:
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.
Final Notes
Hopefully, that gave you some insight into MCP Servers. There's plenty to read and watch but one more site I'll recommend is glama.ai they are keeping a fairly comprehensive list of available MCP Servers to download and try out, including other web search tools that more reliable than our toy example. Check it out, and thank you for following along.
The above is the detailed content of Building a Model Context Protocol Server using Jina.ai and FastMCP in Python. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Python's unittest and pytest are two widely used testing frameworks that simplify the writing, organizing and running of automated tests. 1. Both support automatic discovery of test cases and provide a clear test structure: unittest defines tests by inheriting the TestCase class and starting with test\_; pytest is more concise, just need a function starting with test\_. 2. They all have built-in assertion support: unittest provides assertEqual, assertTrue and other methods, while pytest uses an enhanced assert statement to automatically display the failure details. 3. All have mechanisms for handling test preparation and cleaning: un

PythonisidealfordataanalysisduetoNumPyandPandas.1)NumPyexcelsatnumericalcomputationswithfast,multi-dimensionalarraysandvectorizedoperationslikenp.sqrt().2)PandashandlesstructureddatawithSeriesandDataFrames,supportingtaskslikeloading,cleaning,filterin

Dynamic programming (DP) optimizes the solution process by breaking down complex problems into simpler subproblems and storing their results to avoid repeated calculations. There are two main methods: 1. Top-down (memorization): recursively decompose the problem and use cache to store intermediate results; 2. Bottom-up (table): Iteratively build solutions from the basic situation. Suitable for scenarios where maximum/minimum values, optimal solutions or overlapping subproblems are required, such as Fibonacci sequences, backpacking problems, etc. In Python, it can be implemented through decorators or arrays, and attention should be paid to identifying recursive relationships, defining the benchmark situation, and optimizing the complexity of space.

To implement a custom iterator, you need to define the __iter__ and __next__ methods in the class. ① The __iter__ method returns the iterator object itself, usually self, to be compatible with iterative environments such as for loops; ② The __next__ method controls the value of each iteration, returns the next element in the sequence, and when there are no more items, StopIteration exception should be thrown; ③ The status must be tracked correctly and the termination conditions must be set to avoid infinite loops; ④ Complex logic such as file line filtering, and pay attention to resource cleaning and memory management; ⑤ For simple logic, you can consider using the generator function yield instead, but you need to choose a suitable method based on the specific scenario.

Future trends in Python include performance optimization, stronger type prompts, the rise of alternative runtimes, and the continued growth of the AI/ML field. First, CPython continues to optimize, improving performance through faster startup time, function call optimization and proposed integer operations; second, type prompts are deeply integrated into languages ??and toolchains to enhance code security and development experience; third, alternative runtimes such as PyScript and Nuitka provide new functions and performance advantages; finally, the fields of AI and data science continue to expand, and emerging libraries promote more efficient development and integration. These trends indicate that Python is constantly adapting to technological changes and maintaining its leading position.

Python's socket module is the basis of network programming, providing low-level network communication functions, suitable for building client and server applications. To set up a basic TCP server, you need to use socket.socket() to create objects, bind addresses and ports, call .listen() to listen for connections, and accept client connections through .accept(). To build a TCP client, you need to create a socket object and call .connect() to connect to the server, then use .sendall() to send data and .recv() to receive responses. To handle multiple clients, you can use 1. Threads: start a new thread every time you connect; 2. Asynchronous I/O: For example, the asyncio library can achieve non-blocking communication. Things to note

Polymorphism is a core concept in Python object-oriented programming, referring to "one interface, multiple implementations", allowing for unified processing of different types of objects. 1. Polymorphism is implemented through method rewriting. Subclasses can redefine parent class methods. For example, the spoke() method of Animal class has different implementations in Dog and Cat subclasses. 2. The practical uses of polymorphism include simplifying the code structure and enhancing scalability, such as calling the draw() method uniformly in the graphical drawing program, or handling the common behavior of different characters in game development. 3. Python implementation polymorphism needs to satisfy: the parent class defines a method, and the child class overrides the method, but does not require inheritance of the same parent class. As long as the object implements the same method, this is called the "duck type". 4. Things to note include the maintenance

The core answer to Python list slicing is to master the [start:end:step] syntax and understand its behavior. 1. The basic format of list slicing is list[start:end:step], where start is the starting index (included), end is the end index (not included), and step is the step size; 2. Omit start by default start from 0, omit end by default to the end, omit step by default to 1; 3. Use my_list[:n] to get the first n items, and use my_list[-n:] to get the last n items; 4. Use step to skip elements, such as my_list[::2] to get even digits, and negative step values ??can invert the list; 5. Common misunderstandings include the end index not
