Step by step build a complete Data Quality Skill from scratch. “Please analyze this Excel file and give me a data quality report.” we will build skill like this.
SKILL.md is a standardized markdown file that defines a specific “capability” or “skill” for an AI Agent. It is the “user manual” that tells the LLM exactly what a particular tool/function can do, when to use it, how to use it, and what the expected output looks like. It turns a raw Python function into a teachable, reusable “expertise” for the Agent. A in CN: SKILL.md 是一个标准化的 Markdown 文件,用于为 AI Agent 定义一项特定的“能力”或“技能”。它是给 LLM 看的“用户手册”,准确告诉模型某个工具/函数能做什么、何时使用、如何使用以及预期的输出长什么样。它把一个原始的 Python 函数变成一个可教学、可复用的 Agent “专长”。
Content and Structure of SKILL.md
A complete SKILL.md typically contains 5 core sections. Each section plays a specific role in guiding the LLM’s behavior. A in CN: 一个完整的 SKILL.md 通常包含 5 个核心部分。每个部分在引导 LLM 行为方面都扮演着特定的角色。
This is a mandatory YAML block at the very top of the file, enclosed by ---. It contains machine-readable metadata. The most critical field here is description. A in CN: 这是文件最顶部的强制 YAML 块,由 --- 包围。它包含机器可读的元数据。这里最关键的字段是 description。
2. Description
描述 – 本单元核心!
This is a concise, high-signal, keyword-rich sentence or two that tells the LLM’s router (the top-level orchestrator) what this skill does and when to trigger it. It is the “sales pitch” for the skill. The orchestrator reads all descriptions of all available skills and selects the most relevant one for the user’s query. If your description is vague, the orchestrator will never choose it. CN: 这是一到两句简洁、高信号、关键词丰富的句子,告诉 LLM 的路由器(顶层编排器)这个技能做什么以及何时触发它。它是该技能的“推销词”。编排器会读取所有可用技能的所有描述,并为用户的查询选择最相关的一个。如果你的描述含糊不清,编排器永远不会选择它。
3. Steps
执行步骤
A numbered list of clear, atomic, actionable instructions for the Agent to execute. The Agent will follow these steps sequentially. This is where you break down a complex task into a workflow. CN: 一个编号列表,包含清晰、原子化、可操作的指令供 Agent 执行。Agent 将按顺序遵循这些步骤。这是你将复杂任务分解为工作流的地方。
4. Examples
示例
At least 2-3 concrete examples of user inputs and expected outputs (or thought processes). Examples are extremely powerful for LLMs (few-shot learning within the skill). They align the model’s output style and logic to your expectation. CN: 至少 2-3 个具体的用户输入和预期输出(或思考过程)的示例。示例对 LLM 极其有效(技能内的 few-shot 学习)。它们使模型的输出风格和逻辑与你的期望保持一致。
5. Constraints / Safety
约束/安全
Explicit boundaries, disallowed actions, and failure handling. This is the “guardrails” section. CN: 明确的边界、禁止的操作和失败处理。这是“护栏”部分。
</> YAML
description: Analyze Excel files and produce data quality findings, summaries, and insights.
这个更加重要。它告诉 Agent:这个 Skill 是干什么的,以及什么时候可能需要它。
例如用户说:”Please analyze this Excel file and find duplicate records.”
Agent 就可以判断:
User request
↓
Excel analysis?
↓
Yes
↓
excel-data-analysis Skill
所以:
name 解决:Who are you?
description 解决:What are you for?
4. Purpose
</> Markdown
# Excel Data Analysis
## Purpose
This skill provides a structured workflow for analyzing Excel
files, identifying data quality issues, and producing
business-oriented findings.
这里是在告诉 Agent:这个 Skill 的总体目标是什么?
Purpose 和 description 不完全一样。
Description: 偏向 “什么时候应该考虑使用我?” e.g. Analyze Excel files…
Purpose: 偏向 “使用我以后,我到底要完成什么事情?” e.g identify data quality issues produce business-oriented findings
5. When to Use
</> Markdown
## When to Use
Use this skill when the user asks to:
- Analyze an Excel workbook
- Profile columns and data types
- Detect missing values
- Detect duplicate records
- Identify inconsistent values
- Produce data quality findings
现在进入最核心的部分。在不同的文章里可能叫不同的名字。 例如:Workflow、Instructions、Steps。反正都是告诉 Agent 如何 一步一步地去做什么,具体怎么做。Instructions 是一个更大的概念。Instructions 可以描述 Workflow,也可以描述规则、约束、方法、注意事项等。 Instructions can describe the Workflow, as well as rules, constraints, methods, and other guidance.
如果细化一下:
概念
EN
CN
Instructions
The actual guidance/rules for performing the task
完成任务时应该遵循的指导和规则
Workflow
The overall sequence/flow of the work
整个工作的流程
Step
One individual stage/action within the workflow
Workflow 中的一个具体步骤
Why can’t we just write one sentence?- “Analyze the Excel file and generate a data quality report.”
This sentence is not wrong. But it does not specify:
What should happen first? What should happen next? What should be checked? When should processing stop? When should processing continue? How should the result be validated? What should the final output contain?
</> Markdown
## Instructions
Follow these steps:
### Step 1: Inspect the workbook
Identify:
- Workbook name
- Sheet names
- Number of rows
- Number of columns
- Column names
### Step 2: Profile the data
For each column:
- Determine data type
- Calculate null count
- Calculate distinct count
- Identify suspicious values
### Step 3: Check data quality
Check for:
- Missing values
- Duplicate records
- Invalid formats
- Inconsistent categorical values
### Step 4: Summarize findings
Rank issues by:
1. Severity
2. Business impact
3. Number of affected records
The most important principle: Be specific, actionable, and verifiable. 具体、可操作、可检查。
7.2 Step granularity
Step 的粒度. 每一个 Step 都代表一个有意义的工作阶段。
Each Step represents a meaningful phase of work. A Step can contain substeps 里面可以有子步骤. e.g.
### Step 3 — Detect Data Quality Issues
Check the following categories:
1. Missing values
- Calculate null count.
- Calculate null percentage.
2. Duplicates
- Detect duplicate rows.
- Detect duplicate business keys when defined.
3. Data types
- Compare actual types with expected types.
4. Invalid values
- Check values against available business rules.
7.3 Steps can contain conditions
Step 可以有条件. e.g.
### Step 4 — Validate Findings
1. If a business rule is available:
- Validate the data against the rule.
2. If no business rule is available:
- Report the observed anomaly.
- Do not assume that the anomaly is a business error.
3. If the evidence is insufficient:
- Do not report a definitive violation.
- Mark the finding as requiring confirmation.
因此好的 Step 可以包含:
If
When
Unless
Otherwise
这些条件。
8. Constraints
</>Markdown
## Constraints
- Do not modify the original Excel file.
- Do not delete records.
- Do not infer business meaning without evidence.
- Do not silently correct source data.
- Clearly distinguish facts from assumptions.
这个非常容易被忽略。它解决:Agent 什么不能做?
如果没有 Constraints,Agent 可能:发现拼写错误 ↓ 直接修改 ↓ 保存文件
但是 Skill 可以规定:”Do not modify the original file.”
于是:
Original file ↓ Read only ↓ Analyze ↓ Report problems
这就是 Skill 的行为边界。
9. Resources
假设我们还有一个 Python 工具:scripts/profile_excel.py
</> Markdown
## Resources
Use the following resources when needed:
- `scripts/profile_excel.py`
- Use this script to profile Excel files.
- `references/data-quality-rules.md`
- Contains standard data quality rules.
## Output Format
Return the analysis using the following structure:
### Executive Summary
Briefly summarize the overall data quality.
### Findings
| Issue | Severity | Affected Records | Recommendation |
|---|---|---:|---|
### Details
Explain each significant issue.
### Recommendations
Provide recommended next steps.
11. Examples
## Examples
### Example 1
User:
"Analyze customers.xlsx and find data quality issues."
Expected behavior:
1. Inspect workbook
2. Profile columns
3. Check missing values
4. Check duplicates
5. Check inconsistent values
6. Produce a structured report
A Complete SKILL.md Example
---name: excel-data-analysis
description: Analyze Excel files, identify data quality issues, and produce structured findings and recommendations.
---# Excel Data Analysis
## Purpose
This skill provides a structured workflow for analyzing Excel
workbooks, identifying data quality issues, and producing
business-oriented findings.
## When to Use
Use this skill when the user asks to:
- Analyze an Excel workbook
- Profile columns and data types
- Detect missing values
- Detect duplicate records
- Identify inconsistent values
- Produce data quality findings
Do not use this skill for:
- Creating presentations
- General spreadsheet formatting
- Writing Excel formulas without data analysis
## Capabilities
This skill can:
1. Inspect workbook structure
2. Profile columns
3. Detect missing values
4. Detect duplicate records
5. Detect inconsistent values
6. Generate a data quality summary
## Instructions
### Step 1: Inspect the workbook
Identify:
- Workbook name
- Sheet names
- Number of rows
- Number of columns
- Column names
### Step 2: Profile the data
For each column:
- Determine data type
- Calculate null count
- Calculate distinct count
- Identify suspicious values
### Step 3: Check data quality
Check for:
- Missing values
- Duplicate records
- Invalid formats
- Inconsistent categorical values
### Step 4: Analyze findings
Rank issues based on:
1. Severity
2. Business impact
3. Number of affected records
### Step 5: Produce the report
Generate the output using the required format.
## Constraints
- Do not modify the original Excel file.
- Do not delete records.
- Do not silently correct source data.
- Do not infer business meaning without evidence.
- Clearly distinguish facts from assumptions.
## Resources
Use the following resources when needed:
- `scripts/profile_excel.py`
- Use this script to profile Excel files.
- `references/data-quality-rules.md`
- Contains standard data quality rules.
## Output Format### Executive Summary
Provide a concise summary of the overall data quality.
### Findings
| Issue | Severity | Affected Records | Recommendation |
|---|---|---:|---|
### Details
Explain significant findings and provide supporting evidence.
### Recommendations
Provide practical next steps.
## Examples
### Example 1
User:
"Analyze customers.xlsx and identify data quality issues."
Expected behavior:
1. Inspect the workbook.
2. Profile the columns.
3. Check missing values.
4. Check duplicates.
5. Check inconsistent values.
6. Rank the findings.
7. Produce the structured report.
In AI Agent terms: Tool = a callable function (e.g., get_weather, run_sql). Capability = a complete skill (e.g., “Data Quality Reporting”) that orchestrates tools, prompts, and logic to achieve a business outcome. CN: 在AI Agent术语中:工具 = 一个可调用函数(如 get_weather、run_sql)。能力 = 一项完整技能(如“数据质量报告”),它编排工具、提示词和逻辑来实现业务结果。
The Relationship
A Capability uses Tools, not the other way around. 能力(Capability)使用工具(Tools),而不是反过来。
One Capability can use 0, 1, or many Tools. 一个能力可以使用0个、1个或多个工具。
The Capability defines the “what” and the “why”; the Tool defines the “how”. 能力定义“做什么”和“为什么做”;工具定义“怎么做”。
The Capability also includes a System Prompt (role), an output format, error handling, and retry logic – all invisible to the LLM’s top-level decision maker. 能力还包括系统提示词(角色)、输出格式、错误处理和重试逻辑——所有这些对LLM的顶层决策者都是不可见的。
A “Public MCP Server Directory” is a centralized place where MCP server implementations are listed, categorized, and made discoverable by developers and AI agents. Think of it like npm for Node.js packages, or Hugging Face for ML models — but specifically for MCP servers.
Imagine you built a power adapter (your MCP server) that lets your AI assistant talk to a specific device (like a database or a GitHub repo). A public directory is like an online hardware store catalog — it lists all available adapters, tells you what each one does, who made it, and how to plug it in. Without this catalog, you’d have to stumble upon each adapter by word of mouth or random internet searches.
There is a fundamental distribution problem in the MCP ecosystem. You can build the best MCP server in the world, but if nobody can find it, it might as well not exist. Directories solve this discovery problem. They are the bridge between server builders and server users.
This is the single most important directory. When AI clients like Claude Desktop, Cursor, and others look for verified servers, this is where the chain of trust starts. Getting listed here signals legitimacy.
These are GitHub repositories that curate MCP servers from across the ecosystem. They are less formal than the official registry but often more comprehensive and up-to-date.
EN: These are dedicated platforms built specifically for MCP server discovery, often with additional features like CLI tools, installation automation, and search.
A Databricks MCP Server is a Model Context Protocol server that exposes Databricks platform capabilities (Unity Catalog, SQL, Jobs, Clusters, etc.) as MCP tools that AI agents can dynamically discover and call.
CN: Databricks MCP Server 是一个 MCP 服务器,它将 Databricks 平台的能力(Unity Catalog、SQL、Jobs、Clusters 等)暴露为 MCP 工具,让 AI Agent 可以动态发现和调用这些工具。
Databricks provides three types of MCP servers:
CN: Databricks 提供三种类型的 MCP 服务器:
Type / 类型
EN Description
CN 说明
Managed MCP
Pre-configured, ready-to-use servers for Vector Search, Genie spaces, SQL, and Unity Catalog functions
Claude Desktop Connection is the process of configuring Anthropic’s Claude desktop application to communicate with local MCP (Model Context Protocol) servers via stdio (standard input/output) transport.
CN: Claude Desktop 连接是指将 Anthropic 的 Claude 桌面应用程序配置为通过 stdio(标准输入/输出)传输方式与本地 MCP(模型上下文协议)服务器通信的过程。
The @app.resource() decorator in MCP Python SDK marks a function as a resource provider—a function that returns data (text, JSON, binary) when the AI requests a specific URI.
CN: MCP Python SDK 中的 @app.resource() 装饰器,把一个函数标记为资源提供者——当 AI 请求某个特定 URI 时,这个函数返回数据(文本、JSON、二进制)。
The @app.resource() decorator registers a function as a resource handler. The function must return either a string, a types.TextContent, or a types.Resource object.
# ============================================================
# MCP Server with @app.resource() and Error Handling
# 带 @app.resource() 和错误处理的 MCP 服务器
# ============================================================
import asyncio
import json
import logging
from typing import Optional, List, Dict, Any
# MCP SDK imports / MCP SDK 导入
from mcp.server.fastmcp import FastMCP
import mcp.types as types
from mcp.shared.exceptions import McpError
# Configure logging / 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# ============================================================
# 1. Create MCP Server instance / 创建 MCP 服务器实例
# ============================================================
# FastMCP is the high-level server class that handles all the protocol details
# FastMCP 是高层服务器类,处理所有协议细节
mcp = FastMCP(
name="data-engineering-mcp-server",
version="1.0.0",
description="MCP Server for Data Engineering tasks"
)
# ============================================================
# 2. STATIC RESOURCE: Fixed URI, always returns same data
# 静态资源:固定 URI,始终返回相同数据
# ============================================================
# @mcp.resource() registers this function as a resource provider
# @mcp.resource() 把这个函数注册为资源提供者
# The URI "config://settings" is the address the AI uses to access this resource
# URI "config://settings" 是 AI 用来访问此资源的地址
@mcp.resource("config://settings")
async def get_config() -> str:
"""
Returns static configuration settings for the AI.
返回 AI 的静态配置设置。
This is a simple static resource - it always returns the same JSON.
这是一个简单的静态资源——它总是返回相同的 JSON。
"""
# Return as a JSON string / 以 JSON 字符串返回
return json.dumps({
"max_rows_return": 1000,
"default_database": "analytics_prod",
"query_timeout_seconds": 30,
"enable_cache": True
}, indent=2)
# ============================================================
# 3. STATIC RESOURCE with TextContent (more control)
# 带 TextContent 的静态资源(更多控制)
# ============================================================
@mcp.resource("info://version")
async def get_version_info() -> types.TextContent:
"""
Returns version information as TextContent with MIME type.
以 TextContent 返回版本信息,带 MIME 类型。
TextContent allows you to specify the MIME type of the response.
TextContent 允许你指定响应的 MIME 类型。
"""
return types.TextContent(
type="text",
text="MCP Data Engineering Server v1.0.0 (built 2026-07-25)",
# MIME type tells the client how to interpret the content
# MIME 类型告诉客户端如何解释内容
mime_type="text/plain"
)
# ============================================================
# 4. DYNAMIC RESOURCE (Resource Template) with parameter
# 动态资源(资源模板)带参数
# ============================================================
# URI template with {table_name} placeholder - the AI provides the actual value
# URI 模板带 {table_name} 占位符——AI 提供实际值
# Example: AI requests "schema://tables/orders" -> table_name = "orders"
# 例如:AI 请求 "schema://tables/orders" -> table_name = "orders"
@mcp.resource("schema://tables/{table_name}")
async def get_table_schema(table_name: str) -> str:
"""
Returns the schema of a specific database table.
返回特定数据库表的 schema。
This is a dynamic resource - the result depends on the {table_name} parameter.
这是一个动态资源——结果取决于 {table_name} 参数。
Args:
table_name: Name of the table to describe / 要描述的表名
"""
# In production, this would query your database metadata
# 在生产环境中,这会查询你的数据库元数据
# For demo, we return mock schema data / 演示用,返回模拟 schema 数据
# Simulate a database schema lookup / 模拟数据库 schema 查询
mock_schemas: Dict[str, Dict[str, Any]] = {
"orders": {
"columns": [
{"name": "order_id", "type": "BIGINT", "nullable": False},
{"name": "customer_id", "type": "BIGINT", "nullable": False},
{"name": "order_date", "type": "DATE", "nullable": False},
{"name": "total_amount", "type": "DECIMAL(10,2)", "nullable": False},
{"name": "status", "type": "VARCHAR(50)", "nullable": False},
],
"primary_key": "order_id",
"partitioned_by": "order_date"
},
"customers": {
"columns": [
{"name": "customer_id", "type": "BIGINT", "nullable": False},
{"name": "customer_name", "type": "VARCHAR(200)", "nullable": False},
{"name": "email", "type": "VARCHAR(255)", "nullable": True},
{"name": "created_at", "type": "TIMESTAMP", "nullable": False},
],
"primary_key": "customer_id"
}
}
# ============================================================
# ERROR HANDLING: Resource not found
# 错误处理:资源未找到
# ============================================================
# If the requested table doesn't exist, raise an McpError
# 如果请求的表不存在,抛出 McpError
if table_name not in mock_schemas:
# McpError is the standard MCP error type
# McpError 是标准的 MCP 错误类型
# -32002 is the standard error code for "Resource Not Found"[reference:28]
# -32002 是 "资源未找到" 的标准错误码[reference:29]
raise McpError(
code=-32002, # Resource Not Found / 资源未找到
message=f"Table '{table_name}' not found in database schema. "
f"Available tables: {', '.join(mock_schemas.keys())}"
)
# Return the schema as formatted JSON / 以格式化的 JSON 返回 schema
return json.dumps(mock_schemas[table_name], indent=2)
# ============================================================
# 5. DYNAMIC RESOURCE with multiple parameters
# 带多个参数的动态资源
# ============================================================
@mcp.resource("query://results/{query_id}/{format}")
async def get_query_results(query_id: str, format: str) -> str:
"""
Returns cached query results in specified format.
以指定格式返回缓存的查询结果。
This demonstrates a resource with TWO parameters.
这演示了带两个参数的资源。
Args:
query_id: The ID of the saved query / 保存的查询的 ID
format: Output format: 'json' or 'csv' / 输出格式:'json' 或 'csv'
"""
# In production, this would fetch from a cache or database
# 在生产环境中,这会从缓存或数据库获取
# Simulate query results / 模拟查询结果
mock_results = [
{"date": "2026-07-01", "revenue": 125000, "orders": 342},
{"date": "2026-07-02", "revenue": 98000, "orders": 287},
{"date": "2026-07-03", "revenue": 156000, "orders": 415},
]
# ============================================================
# ERROR HANDLING: Invalid parameter value
# 错误处理:无效参数值
# ============================================================
if format not in ["json", "csv"]:
# -32602 is "Invalid params" / -32602 是 "无效参数"
raise McpError(
code=-32602,
message=f"Invalid format '{format}'. Supported formats: json, csv"
)
if format == "csv":
# Convert to CSV format / 转换为 CSV 格式
import csv
from io import StringIO
output = StringIO()
writer = csv.DictWriter(output, fieldnames=mock_results[0].keys())
writer.writeheader()
writer.writerows(mock_results)
return output.getvalue()
# Default: JSON format / 默认:JSON 格式
return json.dumps(mock_results, indent=2)
# ============================================================
# 6. RESOURCE with list of resources (for client discovery)
# 带资源列表的资源(用于客户端发现)
# ============================================================
# @mcp.list_resources() lets the client discover all available resources
# @mcp.list_resources() 让客户端发现所有可用的资源
# This is called automatically by the SDK, but you can customize it
# 这是由 SDK 自动调用的,但你可以自定义它
@mcp.list_resources()
async def list_resources() -> List[types.Resource]:
"""
Returns the list of all resources this server provides.
返回此服务器提供的所有资源的列表。
The client calls this to discover what resources are available.
客户端调用此方法来发现有哪些资源可用。
"""
return [
types.Resource(
uri="config://settings",
name="Configuration Settings",
description="Server configuration settings",
mimeType="application/json"
),
types.Resource(
uri="info://version",
name="Version Information",
description="Server version info",
mimeType="text/plain"
),
# Resource template - uses URI template notation
# 资源模板 - 使用 URI 模板表示法
types.Resource(
uri="schema://tables/{table_name}",
name="Table Schema",
description="Schema of a specific database table",
mimeType="application/json"
),
types.Resource(
uri="query://results/{query_id}/{format}",
name="Query Results",
description="Cached query results in JSON or CSV format",
mimeType="application/json"
),
]
# ============================================================
# 7. TOOL with error handling (for comparison)
# 带错误处理的 TOOL(用于对比)
# ============================================================
@mcp.tool()
async def execute_sql_query(query: str, limit: Optional[int] = None) -> str:
"""
Execute a SQL query and return results.
执行 SQL 查询并返回结果。
This is a TOOL (action) for comparison with RESOURCES (data).
这是一个 TOOL(动作),用于与 RESOURCES(数据)对比。
"""
# ============================================================
# ERROR HANDLING: Tool-specific errors
# 错误处理:Tool 特定的错误
# ============================================================
# Tools should also use McpError for consistent error handling[reference:30]
# Tools 也应该使用 McpError 来实现一致的错误处理[reference:31]
# Validate input / 验证输入
if not query or len(query.strip()) == 0:
raise McpError(
code=-32602, # Invalid params / 无效参数
message="SQL query cannot be empty"
)
# Check for dangerous SQL (simple demo check)
# 检查危险的 SQL(简单演示检查)
dangerous_keywords = ["DROP", "TRUNCATE", "DELETE", "UPDATE", "ALTER"]
upper_query = query.upper()
for keyword in dangerous_keywords:
if keyword in upper_query:
raise McpError(
code=-32603, # Internal error / 内部错误
message=f"Query contains dangerous keyword '{keyword}'. Only SELECT queries are allowed."
)
# Simulate query execution / 模拟查询执行
# In production, this would connect to your database
# 在生产环境中,这会连接你的数据库
mock_result = {
"query": query,
"row_count": 42,
"execution_time_ms": 125,
"results": [
{"id": 1, "value": "sample data 1"},
{"id": 2, "value": "sample data 2"},
][:limit if limit else 2]
}
return json.dumps(mock_result, indent=2)
# ============================================================
# 8. GLOBAL ERROR HANDLER (optional but recommended)
# 全局错误处理器(可选但推荐)
# ============================================================
# You can wrap resource functions with a decorator for consistent error handling
# 你可以用装饰器包装资源函数,实现一致的错误处理
def handle_resource_errors(func):
"""
Decorator that catches exceptions and converts them to McpError.
装饰器,捕获异常并转换为 McpError。
This ensures all resource errors are returned in the MCP standard format.
这确保所有资源错误都以 MCP 标准格式返回。
"""
async def wrapper(*args, **kwargs):
try:
return await func(*args, **kwargs)
except McpError:
# McpError is already in the correct format - re-raise
# McpError 已经是正确格式 - 重新抛出
raise
except Exception as e:
# Unexpected errors - convert to McpError with internal error code
# 意外错误 - 转换为带内部错误码的 McpError
logger.error(f"Unexpected error in resource {func.__name__}: {e}")
raise McpError(
code=-32603, # Internal error / 内部错误
message=f"An unexpected error occurred: {str(e)}"
)
return wrapper
# ============================================================
# 9. SERVER ENTRY POINT / 服务器入口点
# ============================================================
if __name__ == "__main__":
# Run the server with stdio transport (for local communication)
# 使用 stdio 传输运行服务器(用于本地通信)
# This is the most common way to run MCP servers[reference:32]
# 这是运行 MCP 服务器最常见的方式[reference:33]
mcp.run(transport="stdio")
Key Takeaways
要点
EN
CN
@mcp.resource() 注册资源提供者
@mcp.resource() registers a resource provider function
@app.tool() is a Python decorator provided by the MCP Python SDK (specifically through FastMCP) that automatically registers a plain Python function as a remotely callable MCP tool. When you decorate a function with @app.tool(), the framework automatically extracts the function name, parameter types, and docstring to generate the protocol interface information, making the function available for LLMs to call via the MCP protocol.
Suppose you’re building an AI assistant for data engineering. You want the assistant to be able to run SQL queries on your data warehouse. Without @app.tool(), you’d have to write complex JSON-RPC handlers, manually parse incoming requests, validate parameters, execute the query, format the response, and handle errors. With @app.tool(), you just write:
假设你在为数据工程构建一个 AI 助手。你希望助手能对你的数据仓库执行 SQL 查询。没有 @app.tool(),你需要编写复杂的 JSON-RPC 处理器、手动解析传入请求、验证参数、执行查询、格式化响应并处理错误。有了 @app.tool(),你只需写:
@app.tool()
def run_sql_query(sql: str, database: str = "default") -> dict:
"""Execute a SQL query on the specified database and return results."""
# Your SQL execution logic here
return {"rows": [...], "row_count": 42}
The simplest form is decorating a synchronous function with @app.tool(). The framework uses the function name as the tool name, the docstring as the tool description, and the type hints as the input schema.
MCP Python SDK Server initialization is the process of creating an MCP server instance, registering its capabilities (tools, resources, prompts), and starting it to listen for incoming connections from MCP clients (like Claude Desktop, Cursor, or custom clients).
CN: MCP Python SDK Server 初始化是创建 MCP 服务器实例、注册其能力(工具、资源、提示词),并启动服务器以监听来自 MCP 客户端(如 Claude Desktop、Cursor 或自定义客户端)连接的过程。
What Does Server Initialization Include
组件
EN
CN
安装与环境配置
Install MCP SDK and set up Python environment
安装 MCP SDK 并配置 Python 环境
创建 Server 实例
Instantiate FastMCP or MCPServer class
实例化 FastMCP 或 MCPServer 类
注册能力
Register tools, resources, and prompts via decorators
通过装饰器注册工具、资源和提示词
选择传输协议
Choose transport: stdio (local) or HTTP/SSE (remote)
选择传输协议:stdio(本地)或 HTTP/SSE(远程)
启动服务器
Call .run() or use CLI to start the server
调用 .run() 或使用 CLI 启动服务器
Code Implementation
Check “uv ” ststus
uv is an extremely fast Python package and project manager written in Rust. It replaces multiple tools — pip, pip-tools, pipx, poetry, pyenv, and virtualenv — with a single unified tool.
Bash
uv --version
# if return: "uv 0.8.12" or likes this, that means your envirionment has installed "uv"
# if you see: 'uv' is not recognized as an internal or external command,
# that means you have to install uv at first
bash
# EN: Create a new project with uv (recommended package manager)
# CN: 使用 uv 创建新项目(推荐的包管理器)
uv init my-mcp-server
cd my-mcp-server
# EN: Create and activate virtual environment
# CN: 创建并激活虚拟环境
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# EN: Install MCP SDK (v1.x stable for production)
# CN: 安装 MCP SDK(生产环境使用 v1.x 稳定版)
uv add "mcp[cli]>=1.27,<2"
# EN: Or using pip
# CN: 或使用 pip
pip install "mcp[cli]>=1.27,<2"
# EN: Create server file
# CN: 创建服务器文件
touch server.py
Basic Server Initialization
# EN: server.py - Basic MCP Server Initialization
# CN: server.py - 基础 MCP Server 初始化
# EN: Import FastMCP - the high-level framework for building MCP servers
# CN: 导入 FastMCP - 用于构建 MCP 服务器的高级框架
# EN: FastMCP handles all protocol complexities (JSON-RPC, session management, etc.)
# CN: FastMCP 处理所有协议复杂性(JSON-RPC、会话管理等)
from mcp.server.fastmcp import FastMCP
# ============================================================
# EN: Step 1: Create the server instance
# CN: 步骤 1:创建服务器实例
# EN: FastMCP("name") creates a server with a descriptive name
# CN: FastMCP("name") 创建一个带有描述性名称的服务器
# EN: This name appears in client logs and helps identify your server
# CN: 此名称出现在客户端日志中,有助于识别你的服务器
# ============================================================
mcp = FastMCP("My First MCP Server")
# ============================================================
# EN: Step 2: Register a tool (function that LLM can call)
# CN: 步骤 2:注册工具(LLM 可以调用的函数)
# EN: @mcp.tool decorator automatically:
# CN: @mcp.tool 装饰器自动完成:
# EN: - Uses function name as tool name
# CN: - 使用函数名作为工具名
# EN: - Uses docstring as tool description for LLM
# CN: - 使用 docstring 作为给 LLM 的工具描述
# EN: - Uses type hints to generate JSON schema for inputs
# CN: - 使用类型提示生成输入的 JSON schema
# ============================================================
@mcp.tool
def add(a: int, b: int) -> int:
"""Add two integers together.""" # EN: This becomes the tool description
return a + b # CN: 这成为工具的描述
# ============================================================
# EN: Step 3: Register a resource (read-only data for LLM)
# CN: 步骤 3:注册资源(LLM 可用的只读数据)
# EN: @mcp.resource(uri) exposes data at a specific URI
# CN: @mcp.resource(uri) 在特定 URI 下暴露数据
# ============================================================
@mcp.resource("resource://config")
def get_config() -> dict:
"""Provide application configuration to the LLM."""
return {
"app_name": "My MCP Server",
"version": "1.0.0",
"environment": "development"
}
# ============================================================
# EN: Step 4: Register a prompt (pre-written template for users)
# CN: 步骤 4:注册提示词(为用户预写的模板)
# EN: Prompts help users accomplish specific tasks with guidance
# CN: 提示词帮助用户在指导下完成特定任务
# ============================================================
@mcp.prompt
def code_review(code: str) -> str:
"""Generate a code review prompt template."""
return f"""
Please review this code and provide feedback on:
1. Code quality and readability
2. Potential bugs or edge cases
3. Performance considerations
4. Security concerns
Code:
{code}
"""
# ============================================================
# EN: Step 5: Run the server
# CN: 步骤 5:运行服务器
# EN: The if __name__ == "__main__" block ensures the server runs
# CN: if __name__ == "__main__" 块确保服务器运行
# EN: when the file is executed directly (not when imported)
# CN: 当文件被直接执行时(而不是被导入时)
# EN: Default transport is "stdio" - works with Claude Desktop, Cursor, etc.
# CN: 默认传输协议是 "stdio" - 适用于 Claude Desktop、Cursor 等
# ============================================================
if __name__ == "__main__":
# EN: mcp.run() starts the server and blocks until stopped
# CN: mcp.run() 启动服务器并阻塞直到停止
# EN: It handles all connection management for you
# CN: 它为你处理所有连接管理
mcp.run()
A2A (Agent-to-Agent Protocol) is an open standard protocol designed to enable AI agents from different vendors, built with different frameworks, to communicate and collaborate with each other directly.
CN: A2A(Agent-to-Agent Protocol,智能体间协议)是一个开放标准协议,旨在让来自不同供应商、使用不同框架构建的 AI 智能体能够直接相互通信和协作。
Core Content of A2A
Core Actors
角色 (Role)
EN
CN
A2A Client (Client Agent)
An application, service, or AI agent that initiates communication and delegates tasks to remote agents.
发起通信并将任务委托给远程智能体的应用程序、服务或 AI 智能体。
A2A Server (Remote Agent)
An AI agent that exposes an HTTP endpoint, receives requests, processes tasks, and returns results.
暴露 HTTP 端点、接收请求、处理任务并返回结果的 AI 智能体。
Agent Card
A JSON metadata document, typically at /.well-known/agent.json, that describes an A2A Server.
Maintains session continuity across agent boundaries. When a user’s session spans multiple turns, the context ID links each delegated task to the same ongoing conversation.
CN: 跨智能体边界维持会话连续性。当用户的会话跨越多个轮次时,上下文 ID 将每个委托的任务与同一正在进行的对话相关联。
A2A vs MCP: Key Differences
This is the most important concept to understand. MCP and A2A are complementary, not competing.
CN: 这是最重要的概念。MCP 和 A2A 是互补的,不是竞争的。
维度 (Dimension)
MCP (Model Context Protocol)
A2A (Agent-to-Agent)
EN: Purpose
Connects LLM to tools and data sources
Connects agents to other agents
CN: 用途
连接 LLM 到工具和数据源
连接智能体到其他智能体
EN: Direction
Agent down to tools
Agent out to other agents
CN: 方向
智能体 向下 连工具
智能体 向外 连其他智能体
EN: Control
Orchestrator controls tool selection and result synthesis
External agent uses its own reasoning; tools are opaque to orchestrator
CN: 控制
编排器控制工具选择和结果合成
外部智能体使用自己的推理;工具对编排器不透明
EN: Analogy
“How an agent uses its hands and tools”
“How agents talk to each other”
CN: 比喻
“智能体如何使用手和工具”
“智能体之间如何对话”
Key Takeaways
要点 (Point)
EN
CN
A2A 定义
A2A is an open standard for agent-to-agent communication
A2A 是智能体间通信的开放标准
A2A vs MCP
MCP = agent to tools; A2A = agent to agents (complementary)
MCP = 智能体到工具;A2A = 智能体到智能体(互补)
核心组件
Core components: Agent Card, Task, Message, Part, Context ID
核心组件:智能体名片、任务、消息、部件、上下文 ID
Agent Card
Agent Card is a JSON at /.well-known/agent.json describing agent capabilities