Content
# Model Context Protocol(MCP) 编程极速入门
[TOC]
## Introduction
Model Context Protocol (MCP) is an innovative open-source protocol that redefines how large language models (LLMs) interact with the external world. MCP provides a standardized method that allows any large language model to easily connect to various data sources and tools, enabling seamless access and processing of information. MCP is like a USB-C interface for AI applications, providing AI models with a standardized way to connect to different data sources and tools.
<img src=".assets/image-20250223214308430.png" alt="image-20250223214308430">
MCP has the following core functions:
- Resources
- Prompts
- Tools
- Sampling
- Roots
- Transports
Because most of the functions actually serve the Claude client, this article hopes to write an MCP server service for general large language models, so this article will focus on "tools", and other functions will be briefly explained at the end.
The MCP transport layer supports the implementation of 2 protocols: stdio (standard input/output) and SSE (server-sent events). Because stdio is more commonly used, this article will use stdio as an example for explanation.
This article will use Python version 3.11 and use uv to manage the Python project. At the same time, the code will be put on Github at the end of the article, without further ado, let's start!
## Developing an MCP Server
In this section, we will implement a server for web search. First, let's initialize our project with 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 enter the virtual environment
uv venv
.venv\Scripts\activate.bat
# Install dependencies
uv add "mcp[cli]" httpx openai
```
Then we create a file called `web_search.py` to implement our service. MCP provides us with 2 objects: `mcp.server.FastMCP` and `mcp.server.Server`. `mcp.server.FastMCP` is a higher-level encapsulation, so we will use it here.
```python
import httpx
from mcp.server import FastMCP
# # Initialize the FastMCP server
app = FastMCP('web-search')
```
Implementing the execution method is very simple. MCP provides us with a `@mcp.tool()` decorator. We only need to decorate the implementation function with this decorator. The function name will be used as the tool name, the parameters will be used as tool parameters, and the tool and parameters, as well as the return value, will be described through comments.
Here we directly use the Zhipu interface. This interface can not only help us search for relevant result links, but also help us generate the content summarized from the corresponding links, ~~and it is free at this stage~~ (currently it has started charging, 0.03 yuan/time), which is 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 for internet content
Args:
query: Content to search for
Returns:
Summary of 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. Below, we will use the official `Inspector` visualization tool to debug our server.
We can run `Inspector` in two ways:
> Please make sure that the node environment has been installed.
Through npx:
```shell
npx -y @modelcontextprotocol/inspector <command> <arg1> <arg2>
```
The command to run our code is:
```shell
npx -y @modelcontextprotocol/inspector uv run web_search.py
```
Run through mcp dev:
```shell
mcp dev PYTHONFILE
```
The command to run our code is:
```shell
mcp dev web_search.py
```
If the following prompt appears, it means the run is successful. If a connection error is prompted, it may be that the port is occupied. You can see the solution to this issue: https://github.com/liaokongVFX/MCP-Chinese-Getting-Started-Guide/issues/6
<img src=".assets/image-20250223223638135.png" alt="image-20250223223638135">
Then, we open this address, click the `Connect` button on the left to connect to the service we just wrote. Then we switch to the `Tools` column and click the `List Tools` button to see the tool we just wrote, and we can start debugging.
<img src=".assets/image-20250223224052795.png" alt="image-20250223224052795">
## Developing an MCP Client
First, let's see how to call the tools in the MCP server we just developed on the client side.
```python
import asyncio
from mcp.client.stdio import stdio_client
from mcp import ClientSession, StdioServerParameters
```
# Creating 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',
# Running parameters
args=['run', 'web_search.py'],
# Environment variables, default is None, indicating the use of 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': '今天杭州天气'})
print(response)
if __name__ == '__main__':
asyncio.run(main())
```
Because our python script needs to run in a virtual environment, we use `uv` to start our script here.
Below, let's look at a small example of how to let `DeepSeek` call the methods in our MCP Server.
Here we will use `dotenv` to manage our related environment variables. The contents of the .env file are 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()
```
Then we implement a method to call the MCP server to handle the interaction 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 will not call the tool and answer randomly
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 mcp server tool list information
response = await self.session.list_tools()
# Generate function call description information
available_tools = [{
"type": "function",
"function": {
"name": tool.name,
"description": tool.description,
"input_schema": tool.inputSchema
}
} for tool in response.tools]
# Request deepseek, function call description information 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 you need to use the tool, parse the tool
tool_call = content.message.tool_calls[0]
tool_name = tool_call.function.name
tool_args = json.loads(tool_call.function.arguments)
# Execute the 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 data of which tool deepseek returns to call and the data after the tool is executed into 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 to deepseek for producing the final results
response = self.client.chat.completions.create(
model=os.getenv("OPENAI_MODEL"),
messages=messages,
)
return response.choices[0].message.content
return content.message.content
```
Next, we implement the loop to ask questions and 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 the most streamlined code, which does not implement functions such as recording context messages, but is only intended to use the simplest code to understand how to mobilize the MCP server through large language models. This only demonstrates how to connect to a single server. If you expect to connect to multiple MCP servers, it is nothing more than looping the code in `connect_to_server`. You can encapsulate them into a class, and then loop through all the tools in all MCP servers to generate a large `available_tools`, and then call it through the return result of the large language model. I won’t go into details 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
## Sampling Explanation
MCP also provides us with a `Sampling` function. If you understand it literally, it will be confusing, but in fact, this function gives us an interface before and after the tool is executed. We can perform some operations before and after the tool is executed. For example, when calling a tool to delete a local file, it is definitely expected that we confirm before deleting it. Then, you can use this function at this time.
Below we will implement this small function of manual supervision.
First, let's create an MCP server that simulates having the function of deleting files:
```python
# Server side
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 SamplingMessage to trigger sampling callback function
result = await app.get_context().session.create_message(
messages=[
SamplingMessage(
role='user', content=TextContent(
type='text', text=f'是否要删除文件: {file_path} (Y)')
)
],
max_tokens=100
)
# Get the return value of the sampling callback function and process it according to the return value
if result.content.text == 'Y':
return f'文件 {file_path} 已被删除!!'
if __name__ == '__main__':
app.run(transport='stdio')
```
The most important thing here is to create a `SamplingMessage` type message through the `create_message` method, which will send this message to the function corresponding to the sampling callback.
Next, let's create the client code:
```python
# Client side
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 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 final return result after the tool is executed
print(res)
if __name__ == '__main__':
asyncio.run(main())
```
It is important to note that the content printed in the tool cannot actually be displayed in the command line window using `stdio_client`. Therefore, if we want to debug, we can use `mcp.shared.memory.create_connected_server_and_client_session`.
The specific code is as follows:
```python
# Client side
from mcp.shared.memory import (
create_connected_server_and_client_session as create_session
)
# Here you need to introduce the app object of the server side
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())
```
## Claude Desktop Loading MCP Server
Because the following two features are actually provided for the Claude desktop client, let's first talk about how to load our custom MCP Server into the Claude desktop client.
First, let's open the configuration.

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

Then start adding our server. The server needs to be under the `mcpServers` level, and the parameters include `command`, `args`, and `env`. In fact, the parameters are the same as the parameters when the `StdioServerParameters` object is initialized.
```json
{
"mcpServers": {
"web-search-server": {
"command": "uv",
"args": [
"--directory",
"D:/projects/mcp_getting_started",
"run",
"web_search.py"
]
}
}
}
```
Finally, after we save the file and restart the Claude desktop client, we can see our plugin here.


Of course, we can also run the following command directly in our plugin directory to install it directly:
```shell
mcp install web_search.py
```
## Other Features
### Prompt
MCP also provides us with a function to generate Prompt templates. It is also very simple to use, just use the `prompt` decorator to decorate it, the code is as follows:
```python
from mcp.server import FastMCP
app = FastMCP('prompt_and_resources')
@app.prompt('翻译专家')
async def translate_expert(
target_language: str = 'Chinese',
) -> str:
return f'你是一个翻译专家,擅长将任何语言翻译成{target_language}。请翻译以下内容:'
if __name__ == '__main__':
app.run(transport='stdio')
```
Then we add our new MCP server using the method of configuring the Claude desktop client MCP server mentioned in the previous section. Then we can click the icon in the lower right corner to start using it.
It will let us 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, and also support 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():
# 返回的是,当用户使用这个资源时,资源的内容
return 'Echo!'
@app.resource('greeting://{name}')
async def get_greeting(name):
return f'Hello, {name}!'
if __name__ == '__main__':
app.run(transport='stdio')
```
Then, let's take a look at the Claude desktop client.

It is important to note here that the Claude desktop client cannot currently read the wildcard path set by the resource decorator `greeting://{name}`, which will be supported in the future. However, in our client code, it can be used as a resource template. The specific code is as follows:
```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()
# 获取无通配符的资源列表
res = await session.list_resources()
print(res)
# 获取有通配符的资源列表(资源模板)
res = await session.list_resource_templates()
print(res)
# 读取资源,会匹配通配符
res = await session.read_resource(AnyUrl('greeting://liming'))
print(res)
# 获取 Prompt 模板列表
res = await session.list_prompts()
print(res)
# 使用 Prompt 模板
res = await session.get_prompt(
'翻译专家', arguments={'target_language': '英语'})
print(res)
if __name__ == '__main__':
asyncio.run(main())
```
### Lifecycle
The MCP lifecycle is divided into 3 stages:
- Initialization
- Interacting and communicating
- Service is closed
Therefore, we can do some things at the beginning and end of these three stages, such as creating and closing database connections, recording logs, recording tool usage information, etc.
Below, we will take the web search tool as an example, and store the query and the query results when the tool is called into a global context as a cache, to see how the lifecycle is used. 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
# 初始化一个生命周期上下文对象
class AppContext:
# 里面有一个字段用于存储请求历史
histories: dict
@asynccontextmanager
async def app_lifespan(server):
# 在 MCP 初始化时执行
histories = {}
try:
# 每次通信会把这个上下文通过参数传入工具
yield AppContext(histories=histories)
finally:
# 当 MCP 服务关闭时执行
print(histories)
app = FastMCP(
'web-search',
# 设置生命周期监听函数
lifespan=app_lifespan
)
@app.tool()
# 第一个参数会被传入上下文对象
async def web_search(ctx: Context, query: str) -> str:
"""
搜索互联网内容
Args:
query: 要搜索内容
Returns:
搜索结果的总结
"""
# 如果之前问过同样的问题,就直接返回缓存
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)
# 将查询值和返回值存入到 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 can easily 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()
# 获取工具列表
tools = await load_mcp_tools(session)
# 创建并使用 ReAct agent
agent = create_react_agent(model, tools)
agent_response = await agent.ainvoke({'messages': '杭州今天天气怎么样?'})
```
For more detailed usage, please refer to: https://github.com/langchain-ai/langchain-mcp-adapters
## DeepSeek + cline + Custom MCP = Picture and Text Master
Finally, let's use the cline plugin of VsCode to build a picture and text master application through DeepSeek and our custom image generation mcp server. Without further ado, let's start directly.
First, let's build our image generation mcp server. Here we directly use the `FLUX.1-schnell` model on huggingface. The address is: https://huggingface.co/spaces/black-forest-labs/FLUX.1-schnell . Here we will not use the `gradio_client` library, but will use `httpx` to manually create one, because using the `gradio_client` library may cause encoding errors. The specific code is as follows:
```python
# image_server.py
import json
import httpx
from mcp.server import FastMCP
app = FastMCP('image_server')
@app.tool()
async def image_generation(image_prompt: str):
"""
生成图片
:param image_prompt: 图片描述,需要是英文
:return: 图片保存到的本地路径
"""
async with httpx.AsyncClient() as client:
data = {'data': [image_prompt, 0, True, 512, 512, 3]}
# 创建生成图片任务
response1 = await client.post(
'https://black-forest-labs-flux-1-schnell.hf.space/call/infer',
json=data,
headers={"Content-Type": "application/json"}
)
# 解析响应获取事件 ID
response_data = response1.json()
event_id = response_data.get('event_id')
if not event_id:
return '无法获取事件 ID'
# 通过流式的方式拿到返回数据
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 MCP Inspector to debug our tool.
```shell
mcp dev image_server.py
```

Then 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 we save it, the small dot here is green, which means our server is connected, and then we can start using it.

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

We can see that it correctly calls our tool

Finally, you can see the generated article.

## Deploying MCP Services to the Cloud with Serverless
Above, we discussed how to use the local MCP service. However, sometimes we want to directly deploy the MCP service to the cloud for direct invocation, saving the trouble of local downloading and startup. At this point, we need to use MCP's SSE protocol.
Now, let's write an MCP service using the SSE protocol. It's simple to implement; just set the `transport` parameter in our final `run` command to `sse`. Below, we'll use the web search example from above to implement it. The specific code is 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 the internet for 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 protocol that can be set:
- host: Service address, defaults to `0.0.0.0`
- port: Service port, defaults to 8000. In the code above, I set it to `9000`
- sse_path: SSE route, defaults to `/sse`
Now, we can directly write 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': '杭州今天天气'})
print(res)
if __name__ == '__main__':
asyncio.run(main())
```
We can see that it works normally and has searched for content:
<img src=".assets/image-20250406152518223.png" alt="image-20250406152518223">
Of course, we can also use `mcp dev sse_web_search.py` to test. Note that the `Transport Type` needs to be changed to `SSE`, and then fill in our local service address below.
<img src=".assets/image-20250406153106098.png" alt="image-20250406153106098">
Once everything is tested and there are no problems, we will deploy it to the cloud using a serverless approach. Here, we choose Alibaba Cloud's Function Compute service. First, we go to the `Function Compute FC 3.0`'s `Functions` menu and click `Create Function` to create our service. The address is: https://fcnext.console.aliyun.com/cn-hangzhou/functions
<img src=".assets/image-20250406153655185.png" alt="image-20250406153655185">
Here, we choose `Web Function`, and for the runtime environment, we choose `Python 10`. For the code upload method, you can choose according to your needs. Since I only have one Python file here, I will directly choose `Use Sample Code`, so I can directly overwrite my code later. I will keep the startup command and listening port as default (**the port needs to be consistent with the code**).
You can set the apikey used in the code as an environment variable, but I won't set it here. The final setting screenshot is as follows:
<img src=".assets/image-20250406154115438.png" alt="image-20250406154115438">
In the advanced settings, I enabled the log function for easy debugging.
<img src=".assets/image-20250406154228341.png" alt="image-20250406154228341">
After setting, click Create. It will jump to the code editing section, and then we copy the previous code into it.
<img src=".assets/image-20250406154441634.png" alt="image-20250406154441634">
After completion, let's install the dependencies. We click `Edit Layer` in the upper right corner. By default, there will be a default flask layer, because the initial template uses flask, we don't need it here. We delete it and add an mcp layer. Select `Add Official Public Layer`, and then search for `mcp` to see a Python version of the MCP layer, which contains all the dependencies used by MCP.
<img src=".assets/image-20250406154753623.png" alt="image-20250406154753623">
If you have other third-party dependencies, you can first search to see if there are any in the public layer. If not, you can build a custom layer yourself. Just click here, you only need to provide a `requirements` list, which will not be described in detail here.
<img src=".assets/image-20250406154935751.png" alt="image-20250406154935751">
After we have set everything up, click Deploy in the lower right corner.
Then we return to our code editing page. At this time, we click Deploy Code in the upper left corner again. After waiting for one or two seconds, it will prompt that the code has been deployed successfully. At this point, our MCP service has been deployed to the cloud.
<img src=".assets/image-20250406155135563.png" alt="image-20250406155135563">
> 20250409 Update: I don't know if the official saw this article, but now you can directly select `MCP Runtime` when running, so you don't need to manually add the `MCP Layer` in the layer.
>
> <img src=".assets/image-20250409213302652.png" alt="image-20250409213302652">
Then, we switch to `Configuration`'s `Trigger`, and we can see the URL address we use to access. Of course, you can also bind your own domain name.
<img src=".assets/image-20250406155353662.png" alt="image-20250406155353662">
Then, we can use our client code above to test.
```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': '杭州今天天气'})
print(res)
if __name__ == '__main__':
asyncio.run(main())
```
If we find an error in the client, don't panic. We can directly find the corresponding error request in the log and click `Request Log` to view the error and fix it.
<img src=".assets/image-20250406155803071.png" alt="image-20250406155803071">
At this point, our MCP service has been deployed to the cloud, and we can directly use it anywhere.
For example, in `Cherry-Studio`, we can set it up like this:
<img src=".assets/image-20250406160152782.png" alt="image-20250406160152782">
In `Cline`:
<img src=".assets/image-20250406160709759.png" alt="image-20250406160709759">
In `Cursor`:
<img src=".assets/image-20250406161055717.png" alt="image-20250406161055717">
```json
{
"mcpServers": {
"web-search": {
"url": "https://mcp-test-whhergsbso.cn-hangzhou.fcapp.run/sse"
}
}
}
```
So far, the entire MCP Getting Started Guide is here. Subsequent updates will be made later. 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
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.
Filesystem
Node.js MCP Server for filesystem operations with dynamic access control.
Sequential Thinking
A structured MCP server for dynamic problem-solving and reflective thinking.
git
A Model Context Protocol server for Git automation and interaction.