Content
# Model Context Protocol (MCP) Quick Start Guide
[TOC]
## Introduction
The Model Context Protocol (MCP) is an innovative open-source protocol that redefines the way large language models (LLM) interact with the external world. MCP provides a standardized approach that allows any large language model to easily connect to various data sources and tools, enabling seamless access to and processing of information. MCP acts like a USB-C interface for AI applications, offering a standardized way for AI models to connect to different data sources and tools.

MCP has several core features:
- Resources 资源
- Prompts 提示词
- Tools 工具
- Sampling 采样
- Roots 根目录
- Transports 传输层
Since most features primarily serve the Claude client, this document aims to focus on the MCP server's service for general large language models, with an emphasis on "tools," while other features will be briefly explained at the end.
The transport layer of MCP supports the implementation of two protocols: stdio (standard input/output) and SSE (Server-Sent Events). Since stdio is more commonly used, this document will use stdio as an example for explanation.
This document will use Python version 3.11 and utilize uv to manage the Python project. The code will be available on GitHub at the end of the document. Without further ado, let's get started!
## Developing the MCP Server
In this section, we will implement a server for network search. First, let's initialize our project using uv.
> uv Official Documentation: https://docs.astral.sh/uv/
```shell
# Initialize the Project
uv init mcp_getting_started
cd mcp_getting_started
# Create a Virtual Environment and Activate It
uv venv
.venv\Scripts\activate.bat
# Install Dependencies
uv add "mcp[cli]" httpx openai
```
Next, let's create a file called `web_search.py` to implement our service. MCP provides us with two objects: `mcp.server.FastMCP` and `mcp.server.Server`. We will use `mcp.server.FastMCP`, which is a higher-level wrapper.
```python
import httpx
from mcp.server import FastMCP
# # Initialize FastMCP Server
```python
app = FastMCP('web-search')
```
The implementation method is very simple. MCP provides us with a `@mcp.tool()` decorator, and we just need to decorate the implementation function with this decorator. The function name will serve as the tool name, the parameters will act as tool parameters, and comments will describe the tool, parameters, and return values.
Here we directly use the Zhiyu interface, which not only helps us search for relevant result links but also generates summaries of the articles corresponding to those links. ~~Currently, it is free~~ (it has started charging, 0.03 yuan per use), making it very suitable for us.
> Official documentation: https://bigmodel.cn/dev/api/search-tool/web-search-pro
>
> API Key generation address: https://bigmodel.cn/usercenter/proj-mgmt/apikeys
```python
@app.tool()
async def web_search(query: str) -> str:
"""
Search internet content
Args:
query: The content to search for
Returns:
Summary of the search results
"""
async with httpx.AsyncClient() as client:
response = await client.post(
'https://open.bigmodel.cn/api/paas/v4/tools',
headers={'Authorization': 'Replace with your own API KEY'},
json={
'tool': 'web-search-pro',
'messages': [
{'role': 'user', 'content': query}
],
'stream': False
}
)
res_data = []
for choice in response.json()['choices']:
for message in choice['message']['tool_calls']:
search_results = message.get('search_result')
if not search_results:
continue
for result in search_results:
res_data.append(result['content'])
return '\n\n\n'.join(res_data)
```
Finally, let's add the code to run the server.
```python
if __name__ == "__main__":
app.run(transport='stdio')
```
## Debugging the MCP Server
At this point, we have completed the writing of the MCP server. Next, we will use the official `Inspector` visualization tool to debug our server.
We can run `Inspector` in two ways:
> Please ensure that the node environment is installed.
Using npx:
```shell
npx -y @modelcontextprotocol/inspector <command> <arg1> <arg2>
```
Our command to run this code is:
```shell
npx -y @modelcontextprotocol/inspector uv run web_search.py
```
Running via mcp dev:
```shell
mcp dev PYTHONFILE
```
Our command to run this code is:
```shell
mcp dev web_search.py
```
When the following prompt appears, it indicates that the run was successful. If there is a connection error, it may be due to the port being occupied. You can refer to the solution in this issue: https://github.com/liaokongVFX/MCP-Chinese-Getting-Started-Guide/issues/6

Then, we open this address and click the `Connect` button on the left side to connect to the service we just wrote. Next, we switch to the `Tools` tab and click the `List Tools` button to see the tool we just created, and we can start debugging!

## Developing the MCP Client
First, let's take a look at how to call the tools we just developed in the MCP server from the client.
```python
import asyncio
from mcp.client.stdio import stdio_client
from mcp import ClientSession, StdioServerParameters
```
# Server Parameters for stdio Connection
server_params = StdioServerParameters(
# The command executed by the server, here we use uv to run web_search.py
command='uv',
# The arguments to run
args=['run', 'web_search.py'],
# Environment variables, default is None, indicating to use the current environment variables
# env=None
)
async def main():
# Create stdio client
async with stdio_client(server_params) as (stdio, write):
# Create ClientSession object
async with ClientSession(stdio, write) as session:
# Initialize ClientSession
await session.initialize()
# List available tools
response = await session.list_tools()
print(response)
# Call tool
response = await session.call_tool('web_search', {'query': 'What is the weather in Hangzhou today?'})
print(response)
if __name__ == '__main__':
asyncio.run(main())
```
Since our Python script needs to run in a virtual environment, we start our script using `uv`.
Next, let's look at a small example of how to have `DeepSeek` call methods in our MCP server.
Here we will use `dotenv` to manage our related environment variables. The content of the .env file is as follows:
```shell
OPENAI_API_KEY=sk-89baxxxxxxxxxxxxxxxxxx
OPENAI_BASE_URL=https://api.deepseek.com
OPENAI_MODEL=deepseek-chat
```
First, let's write our `MCPClient` class.
```python
import json
import asyncio
import os
from typing import Optional
from contextlib import AsyncExitStack
from openai import OpenAI
from dotenv import load_dotenv
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
load_dotenv()
class MCPClient:
def __init__(self):
self.session: Optional[ClientSession] = None
self.exit_stack = AsyncExitStack()
self.client = OpenAI()
```
Then we add the `connect_to_server` method to initialize our MCP server's session.
```python
async def connect_to_server(self):
server_params = StdioServerParameters(
command='uv',
args=['run', 'web_search.py'],
env=None
)
stdio_transport = await self.exit_stack.enter_async_context(
stdio_client(server_params))
stdio, write = stdio_transport
self.session = await self.exit_stack.enter_async_context(
ClientSession(stdio, write))
await self.session.initialize()
```
Next, we implement a method to call the MCP server to handle interactions with DeepSeek.
```python
async def process_query(self, query: str) -> str:
# Here we need to constrain the large language model through the system prompt,
# otherwise it may not call the tool and provide random answers
system_prompt = (
"You are a helpful assistant."
"You have the function of online search. "
"Please MUST call web_search tool to search the Internet content before answering."
"Please do not lose the user's question information when searching,"
"and try to maintain the completeness of the question content as much as possible."
"When there is a date related question in the user's question,"
"please use the search function directly to search and PROHIBIT inserting specific time."
)
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": query}
]
# Get all tool list information from the MCP server
response = await self.session.list_tools()
# Generate description information for function call
available_tools = [{
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"input_schema": tool.inputSchema
}
} for tool in response.tools]
# Request deepseek, the description information for function call is passed through the tools parameter
response = self.client.chat.completions.create(
model=os.getenv("OPENAI_MODEL"),
messages=messages,
tools=available_tools
)
# Process the returned content
content = response.choices[0]
if content.finish_reason == "tool_calls":
# If a tool is needed, parse the tool
tool_call = content.message.tool_calls[0]
tool_name = tool_call.function.name
tool_args = json.loads(tool_call.function.arguments)
```python
# Execution Tool
result = await self.session.call_tool(tool_name, tool_args)
print(f"\n\n[Calling tool {tool_name} with args {tool_args}]\n\n")
# Store the tool data returned by deepseek and the data after the tool execution in messages
messages.append(content.message.model_dump())
messages.append({
"role": "tool",
"content": result.content[0].text,
"tool_call_id": tool_call.id,
})
# Return the above results back to deepseek to produce the final result
response = self.client.chat.completions.create(
model=os.getenv("OPENAI_MODEL"),
messages=messages,
)
return response.choices[0].message.content
return content.message.content
```
Next, let's implement the loop for querying and the operation to close the session after exiting.
```python
async def chat_loop(self):
while True:
try:
query = input("\nQuery: ").strip()
if query.lower() == 'quit':
break
response = await self.process_query(query)
print("\n" + response)
except Exception as e:
import traceback
traceback.print_exc()
async def cleanup(self):
"""Clean up resources"""
await self.exit_stack.aclose()
```
Finally, let's complete the code related to running this client.
```python
async def main():
client = MCPClient()
try:
await client.connect_to_server()
await client.chat_loop()
finally:
await client.cleanup()
if __name__ == "__main__":
import sys
asyncio.run(main())
```
This is a minimal code snippet that does not implement context message recording and other features; it is simply to understand how to interact with the MCP Server using the simplest code through a large language model. This example only demonstrates how to connect to a single server. If you expect to connect to multiple MCP servers, you can simply loop through the code in `connect_to_server`, encapsulate them into a class, and then iterate through all the tools in the MCP servers to generate a large `available_tools`, which can then be called based on the results returned by the large language model. This will not be elaborated further here.
> You can refer to the official example: https://github.com/modelcontextprotocol/python-sdk/blob/main/examples/clients/simple-chatbot/mcp_simple_chatbot/main.py
```
## Explanation of Sampling
MCP also provides us with a `Sampling` feature, which might be confusing at first glance, but in reality, this feature gives us an interface to execute some operations before and after the execution of a tool. For example, when calling a tool to delete a local file, we would certainly want to confirm before proceeding with the deletion. This is where this feature comes in handy.
Now, let's implement this small functionality for manual supervision.
First, let's create a simulated MCP server that has the capability to delete files:
```python
# Server
from mcp.server import FastMCP
from mcp.types import SamplingMessage, TextContent
app = FastMCP('file_server')
@app.tool()
async def delete_file(file_path: str):
# Create a SamplingMessage to trigger the sampling callback function
result = await app.get_context().session.create_message(
messages=[
SamplingMessage(
role='user', content=TextContent(
type='text', text=f'Do you want to delete the file: {file_path} (Y)')
)
],
max_tokens=100
)
# Get the return value from the sampling callback function and process it accordingly
if result.content.text == 'Y':
return f'The file {file_path} has been deleted!!'
if __name__ == '__main__':
app.run(transport='stdio')
```
The most important part here is to create a `SamplingMessage` type message using the `create_message` method, which will send this message to the corresponding sampling callback function.
Next, let's create the client code:
```python
# Client
import asyncio
from mcp.client.stdio import stdio_client
from mcp import ClientSession, StdioServerParameters
from mcp.shared.context import RequestContext
from mcp.types import (
TextContent,
CreateMessageRequestParams,
CreateMessageResult,
)
server_params = StdioServerParameters(
command='uv',
args=['run', 'file_server.py'],
)
async def sampling_callback(
context: RequestContext[ClientSession, None],
params: CreateMessageRequestParams,
):
# Get the message sent by the tool and display it to the user
input_message = input(params.messages[0].content.text)
# Send the user input back to the tool
return CreateMessageResult(
role='user',
content=TextContent(
type='text',
text=input_message.strip().upper() or 'Y'
),
model='user-input',
stopReason='endTurn'
)
async def main():
async with stdio_client(server_params) as (stdio, write):
async with ClientSession(
stdio, write,
# Set the method corresponding to sampling_callback
sampling_callback=sampling_callback
) as session:
await session.initialize()
res = await session.call_tool(
'delete_file',
{'file_path': 'C:/xxx.txt'}
)
# Get the return result of the last executed tool
print(res)
if __name__ == '__main__':
asyncio.run(main())
```
It is important to note that currently, the content printed in the tool cannot actually be displayed in the command line window when using `stdio_client`. Therefore, for debugging, we can use `mcp.shared.memory.create_connected_server_and_client_session`.
The specific code is as follows:
```python
# Client
from mcp.shared.memory import (
create_connected_server_and_client_session as create_session
)
# Here we need to import the app object from the server
from file_server import app
async def sampling_callback(context, params):
...
async def main():
async with create_session(
app._mcp_server,
sampling_callback=sampling_callback
) as client_session:
await client_session.call_tool(
'delete_file',
{'file_path': 'C:/xxx.txt'}
)
if __name__ == '__main__':
asyncio.run(main())
```
## Loading MCP Server into Claude Desktop
Since the following two features are actually intended for the Claude desktop client, let's first discuss how to load our custom MCP Server into the Claude desktop client.
First, we need to open the configuration.

We click on the `Developer` menu, then click the `Edit Config` button to open the Claude desktop client configuration file `claude_desktop_config.json`.

Next, we start adding our server. The server needs to be under the `mcpServers` level, with parameters `command`, `args`, and `env`. In fact, the parameters are the same as those used when initializing the `StdioServerParameters` object.
```json
{
"mcpServers": {
"web-search-server": {
"command": "uv",
"args": [
"--directory",
"D:/projects/mcp_getting_started",
"run",
"web_search.py"
]
}
}
}
```
Finally, after saving the file and restarting the Claude desktop client, we will be able to see our plugin here.


Of course, we can also run the following command directly in our plugin's directory to install it:
```shell
mcp install web_search.py
```
## Other Features
### Prompt
MCP also provides us with a feature to generate Prompt templates. It is very easy to use; you just need to decorate it with the `prompt` decorator, as shown in the code below:
```python
from mcp.server import FastMCP
app = FastMCP('prompt_and_resources')
@app.prompt('翻译专家')
async def translate_expert(
target_language: str = 'Chinese',
) -> str:
return f'You are a translation expert, skilled at translating any language into {target_language}. Please translate the following content:'
if __name__ == '__main__':
app.run(transport='stdio')
```
Then we can add our new MCP server using the method discussed in the previous section for configuring the Claude desktop MCP server. After that, we can click the icon in the lower right corner to start using it.
It will prompt us to set the parameters we pass in, and then it will generate an attachment in our chat window.

### Resource
We can also select the preset resources we provide for users on the Claude client, while also supporting custom protocols. The specific code is as follows:
```python
from mcp.server import FastMCP
app = FastMCP('prompt_and_resources')
@app.resource('echo://static')
async def echo_resource():
# The content returned when the user uses this resource
return 'Echo!'
@app.resource('greeting://{name}')
async def get_greeting(name):
return f'Hello, {name}!'
if __name__ == '__main__':
app.run(transport='stdio')
```
Next, let's take a look at the Claude desktop client.

It is important to note that currently, the Claude desktop client cannot read resource decorators set with wildcard paths like `greeting://{name}`, but this will be supported in the future. However, in our client code, it can be used as a resource template, as shown in the following code:
```python
import asyncio
from pydantic import AnyUrl
from mcp.client.stdio import stdio_client
from mcp import ClientSession, StdioServerParameters
server_params = StdioServerParameters(
command='uv',
args=['run', 'prompt_and_resources.py'],
)
async def main():
async with stdio_client(server_params) as (stdio, write):
async with ClientSession(stdio, write) as session:
await session.initialize()
# Get the list of resources without wildcards
res = await session.list_resources()
print(res)
# Get the list of resources with wildcards (resource templates)
res = await session.list_resource_templates()
print(res)
# Read resource, will match wildcards
res = await session.read_resource(AnyUrl('greeting://liming'))
print(res)
# Get the list of Prompt templates
res = await session.list_prompts()
print(res)
# Use Prompt template
res = await session.get_prompt(
'翻译专家', arguments={'target_language': '英语'})
print(res)
if __name__ == '__main__':
asyncio.run(main())
```
### Lifecycle
The MCP lifecycle is divided into three stages:
- Initialization
- In interactive communication
- Service shutdown
Therefore, we can perform certain actions at the beginning and end of these three stages, such as creating and closing database connections, logging, and recording tool usage information.
Below, we will use a web search tool as an example, where the queries made when invoking the tool and the results obtained are stored in a global context as a cache, to illustrate how the lifecycle is utilized. The complete code is as follows:
```python
import httpx
from dataclasses import dataclass
from contextlib import asynccontextmanager
from mcp.server import FastMCP
from mcp.server.fastmcp import Context
@dataclass
```
# Initialize a lifecycle context object
class AppContext:
# Contains a field to store request history
histories: dict
@asynccontextmanager
async def app_lifespan(server):
# Executed during MCP initialization
histories = {}
try:
# This context will be passed as a parameter to the tool during each communication
yield AppContext(histories=histories)
finally:
# Executed when the MCP service shuts down
print(histories)
app = FastMCP(
'web-search',
# Set the lifecycle listener function
lifespan=app_lifespan
)
@app.tool()
# The first parameter will be passed into the context object
async def web_search(ctx: Context, query: str) -> str:
"""
Search for content on the internet
Args:
query: The content to search for
Returns:
A summary of the search results
"""
# If the same question has been asked before, return the cached result directly
histories = ctx.request_context.lifespan_context.histories
if query in histories:
return histories[query]
async with httpx.AsyncClient() as client:
response = await client.post(
'https://open.bigmodel.cn/api/paas/v4/tools',
headers={'Authorization': 'YOUR API KEY'},
json={
'tool': 'web-search-pro',
'messages': [
{'role': 'user', 'content': query}
],
'stream': False
}
)
res_data = []
for choice in response.json()['choices']:
for message in choice['message']['tool_calls']:
search_results = message.get('search_result')
if not search_results:
continue
for result in search_results:
res_data.append(result['content'])
return_data = '\n\n\n'.join(res_data)
# Store the query and return value in histories
ctx.request_context.lifespan_context.histories[query] = return_data
return return_data
if __name__ == "__main__":
app.run()
```
## Using MCP Server in LangChain
Recently, LangChain released a new open-source project `langchain-mcp-adapters`, which makes it easy to integrate the MCP Server into LangChain. Let's take a look at how to use it:
```python
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from langchain_mcp_adapters.tools import load_mcp_tools
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
model = ChatOpenAI(model="gpt-4o")
server_params = StdioServerParameters(
command='uv',
args=['run', 'web_search.py'],
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# Get the list of tools
tools = await load_mcp_tools(session)
# Create and use ReAct agent
agent = create_react_agent(model, tools)
agent_response = await agent.ainvoke({'messages': 'What is the weather like in Hangzhou today?'})
```
For more detailed usage instructions, please refer to: https://github.com/langchain-ai/langchain-mcp-adapters
## DeepSeek + cline + Custom MCP = Image and Text Master
Finally, we will use the cline plugin in VsCode to build an Image and Text Master application through DeepSeek and our custom image-generating MCP server. Without further ado, let's get started.
First, let's build our image-generating MCP server. Here, we will directly use the `FLUX.1-schnell` model available on Hugging Face, which can be found at: https://huggingface.co/spaces/black-forest-labs/FLUX.1-schnell. We will not use the `gradio_client` library; instead, we will manually implement it using `httpx`, as using the `gradio_client` library may lead to encoding errors. The specific code is as follows:
```python
# image_server.py
```python
import json
import httpx
from mcp.server import FastMCP
app = FastMCP('image_server')
@app.tool()
async def image_generation(image_prompt: str):
"""
Generate an image
:param image_prompt: Image description, must be in English
:return: Local path where the image is saved
"""
async with httpx.AsyncClient() as client:
data = {'data': [image_prompt, 0, True, 512, 512, 3]}
# Create a task to generate the image
response1 = await client.post(
'https://black-forest-labs-flux-1-schnell.hf.space/call/infer',
json=data,
headers={"Content-Type": "application/json"}
)
# Parse the response to get the event ID
response_data = response1.json()
event_id = response_data.get('event_id')
if not event_id:
return 'Unable to retrieve event ID'
# Retrieve the returned data via streaming
url = f'https://black-forest-labs-flux-1-schnell.hf.space/call/infer/{event_id}'
full_response = ''
async with client.stream('GET', url) as response2:
async for chunk in response2.aiter_text():
full_response += chunk
return json.loads(full_response.split('data: ')[-1])[0]['url']
if __name__ == '__main__':
app.run(transport='stdio')
```
Then we can use the following command in the virtual environment to open the MCP Inspector for debugging our tool.
```shell
mcp dev image_server.py
```

Next, we install the cline plugin in VsCode. After installing the plugin, we configure our deepseek API key. Then, we click the `MCP Server` button in the upper right corner to open the MCP server list.

Then switch to the `Installed` Tab and click the `Configure MCP Servers` button to edit the custom MCP server.

The configuration is as follows:
```json
{
"mcpServers": {
"image_server": {
"command": "uv",
"args": [
"--directory",
"D:/projects/mcp_getting_started",
"run",
"image_server.py"
],
"env": {},
"disabled": false,
"autoApprove": []
}
}
}
```
After saving, if the small dot here is green, it indicates that our server is connected, and we can start using it.

Then, we open the input box to enter the content of the article we want to write:

We can see that it correctly called our tool.

Finally, we can see the generated article.

## Deploying MCP Services to the Cloud with Serverless
What we discussed above is how to use the local MCP service, but sometimes we want to deploy the MCP service directly to the cloud for direct invocation, which saves us the trouble of downloading and starting it locally. At this point, we need to use the SSE (Server-Sent Events) protocol of MCP to achieve this.
Now, let's write the MCP service using the SSE protocol. It's quite simple; we just need to set the `transport` parameter in our final `run` command to `sse`. Below, we will use the previous network search example to implement this, with the specific code as follows:
```python
# sse_web_search.py
import httpx
from mcp.server import FastMCP
app = FastMCP('web-search', port=9000)
@app.tool()
async def web_search(query: str) -> str:
"""
Search internet content
Args:
query: The content to search for
Returns:
A summary of the search results
"""
async with httpx.AsyncClient() as client:
response = await client.post(
'https://open.bigmodel.cn/api/paas/v4/tools',
headers={'Authorization': 'YOUR API KEY'},
json={
'tool': 'web-search-pro',
'messages': [
{'role': 'user', 'content': query}
],
'stream': False
}
)
res_data = []
for choice in response.json()['choices']:
for message in choice['message']['tool_calls']:
search_results = message.get('search_result')
if not search_results:
continue
for result in search_results:
res_data.append(result['content'])
return '\n\n\n'.join(res_data)
if __name__ == "__main__":
app.run(transport='sse')
```
In `FastMCP`, there are several parameters related to the SSE (Server-Sent Events) protocol that can be set:
- host: Service address, default is `0.0.0.0`
- port: Service port, default is 8000. In the above code, I set it to `9000`
- sse_path: The route for SSE, default is `/sse`
At this point, we can directly write a client code to test it. The specific code is as follows:
```python
import asyncio
from mcp.client.sse import sse_client
from mcp import ClientSession
async def main():
async with sse_client('http://localhost:9000/sse') as streams:
async with ClientSession(*streams) as session:
await session.initialize()
res = await session.call_tool('web_search', {'query': 'What is the weather like in Hangzhou today?'})
print(res)
if __name__ == '__main__':
asyncio.run(main())
```
We can see that it works normally and has searched for content:

Of course, we can also test it using `mcp dev sse_web_search.py`. Here, it is important to note that the `Transport Type` needs to be changed to `SSE`, and then fill in our local service address below.

Once everything has been tested without issues, we will deploy it to the cloud in a serverless manner. Here, we choose Alibaba Cloud's Function Compute service. First, we enter the `Function` menu of Alibaba Cloud's `Function Compute FC 3.0` and click `Create Function` to create our service. The address is: https://fcnext.console.aliyun.com/cn-hangzhou/functions

We choose `Web Function`, and for the runtime environment, we select `Python 10`. The code upload method can be chosen according to everyone's needs. Since I only have one Python file, I directly select `Use Sample Code`, so I can just overwrite my code later. I keep the startup command and listening port as default (**the port needs to be consistent with the code**).
For environment variables, you can set the apikey used in the code as an environment variable, but I will not set it here. The final setup screenshot is as follows:

In the advanced settings, I enabled the logging feature for easier debugging.

After the settings are complete, click create. It will redirect to the code editing section, and we can copy our previous code into it.

Once done, we need to install the dependencies. We click on `Edit Layer` in the upper right corner. By default, there will be a default Flask layer since the initial template uses Flask, but we don't need it here. We delete it and add an MCP layer. Choose `Add Official Public Layer`, then search for `mcp` to find a Python version of the MCP layer, which contains all the dependencies used by MCP.

If you have other third-party dependencies, you can search to see if there are any in the public layers. If not, you can build a custom layer yourself. Just click here and provide a `requirements` list, which I won't elaborate on here.

Once we have completed all the settings, click the deploy button in the lower right corner.
Then we return to the code editing page. At this point, we click on the deploy code in the upper left corner. After waiting a second or two, it will prompt that the code deployment was successful. At this point, our MCP service has been deployed to the cloud.

> Updated on 20250409: I don't know if the official team saw this article, but now you can directly choose `MCP Runtime` during runtime selection, so you no longer need to manually add the `MCP Layer` in the layers section.
>
> 
Next, we switch to the `Configuration`'s `Triggers`, where we can see the URL address we use to access it. Of course, you can also bind your own domain name.

Now we can use our client code above to test it.
```python
import asyncio
from mcp.client.sse import sse_client
from mcp import ClientSession
async def main():
async with sse_client('https://mcp-test-whhergsbso.cn-hangzhou.fcapp.run/sse') as streams:
async with ClientSession(*streams) as session:
await session.initialize()
res = await session.call_tool('web_search', {'query': 'What is the weather like in Hangzhou today?'})
print(res)
if __name__ == '__main__':
asyncio.run(main())
```
If we find that there are errors in the client, there's no need to panic. We can directly find the corresponding error request in the logs and click `Request Log` to view the error for fixing.

At this point, our MCP service has been deployed to the cloud, and we can use it directly from anywhere.
For example, in `Cherry-Studio`, we can set it up like this:

In `Cline`:

In `Cursor`:

```json
{
"mcpServers": {
"web-search": {
"url": "https://mcp-test-whhergsbso.cn-hangzhou.fcapp.run/sse"
}
}
}
```
Thus, the entire MCP getting started tutorial comes to an end. Any further updates will be made later. The related code will be placed in the GitHub repository: https://github.com/liaokongVFX/MCP-Chinese-Getting-Started-Guide
Connection Info
You Might Also Like
MarkItDown MCP
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
Time
A Model Context Protocol server for time and timezone conversions.
Filesystem
Node.js MCP Server for filesystem operations with dynamic access control.
Continuous-Claude-v2
Continuous-Claude-v2 enables session continuity and efficient MCP execution.
Continuous-Claude
Continuous-Claude enhances session continuity and efficiency in MCP execution.
Cloudfare
MCP servers for connecting Cloudflare services with LLMs using natural language.