使用说明
简单MCP服务器(Starlette,可流式传输http)
Python 3.11中使用Starlette的最小MCP服务器:
streamable-http运输(POST /mcp)- 承载令牌身份验证(
Authorization: Bearer <token>)使用OAuth风格的挑战元数据 - 工具:
get_locale_date_timeget_wikipedia_pages_json
需求
- python
3.11+
设置
git clone https://github.com/diversen/minimal-mcp-server.git
cd minimal-mcp-server
uv sync
设置环境变量:
cp .env.example .env
export MCP_AUTH_TOKEN="your-very-secret-token"
export MCP_AUTHORIZATION_SERVERS="https://auth.example.com"
export MCP_ALLOWED_ORIGINS="http://localhost:3000,http://127.0.0.1:3000"
export HOST="0.0.0.0"
export PORT="5000"
.env 变量引用
MCP_AUTH_TOKEN(必填):服务器用于验证请求的固定承载令牌。必须设置。HOST(可选):绑定Uvicorn的地址。默认值可以是0.0.0.0用于本地网络接入。PORT(可选):服务器端口。此项目中建议的默认端口为5000.MCP_ALLOWED_ORIGINS(可选):浏览器客户端的逗号分隔的源代码列表。保留未设置以禁用源过滤。MCP_AUTHORIZATION_SERVERS(可选):发现元数据返回的逗号分隔的OAuth授权服务器URL。仅当您使用真正的OAuth发现时才设置此项。MCP_REQUIRED_SCOPE(可选):在元数据/挑战中公布的作用域名称。适用于OAuth设置;为固定令牌模式留空。MCP_RESOURCE_DOCUMENTATION(可选):受保护MCP资源的文档URL。
对于简单的固定令牌模式,仅 MCP_AUTH_TOKEN 是必需的。
跑
uv run uvicorn server:app --host "${HOST}" --port "${PORT}"
用于开发(自动重新加载 .py 更改):
uv run uvicorn server:app --host "${HOST}" --port "${PORT}" --reload
MCP流程示例
1) initialize
curl -s -X POST "http://127.0.0.1:5000/mcp" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-very-secret-token" \
-d '{
"jsonrpc":"2.0",
"id":1,
"method":"initialize",
"params":{
"protocolVersion":"2025-06-18",
"capabilities":{},
"clientInfo":{"name":"demo-client","version":"0.1.0"}
}
}'
2) tools/list
curl -s -X POST "http://127.0.0.1:5000/mcp" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-very-secret-token" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
3) tools/call
curl -s -X POST "http://127.0.0.1:5000/mcp" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-very-secret-token" \
-d '{
"jsonrpc":"2.0",
"id":3,
"method":"tools/call",
"params":{
"name":"get_locale_date_time",
"arguments":{"locale":"Copenhagen"}
}
}'
维基百科页面JSON(仅返回 query.pages 在 structuredContent):
curl -s -X POST "http://127.0.0.1:5000/mcp" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-very-secret-token" \
-d '{
"jsonrpc":"2.0",
"id":4,
"method":"tools/call",
"params":{
"name":"get_wikipedia_pages_json",
"arguments":{"title":"Earth","language":"en"}
}
}'
身份验证行为
- 缺少/无效的身份验证标头->
401 - 令牌错误->
401 - 缺少服务器令牌配置(
MCP_AUTH_TOKEN) ->500 401包括WWW-Authenticate: Bearer ... resource_metadata=".../.well-known/oauth-protected-resource/mcp"
OAuth发现元数据
这些未经身份验证的端点可用于OAuth资源发现:
GET /.well-known/oauth-protected-resourceGET /.well-known/oauth-protected-resource/mcp
它们返回资源元数据JSON,包括:
resource(您的MCP端点URL)authorization_servers(从MCP_AUTHORIZATION_SERVERS)bearer_methods_supported- 可选的
scopes_supported(从MCP_REQUIRED_SCOPE) - 可选的
resource_documentation(从MCP_RESOURCE_DOCUMENTATION)
注意:此项目现在实现了OAuth风格的发现/挑战约定,但访问令牌验证仍然是使用 MCP_AUTH_TOKEN.
原产地验证
- 如果
MCP_ALLOWED_ORIGINS已设置,请求具有Origin标头必须与其中一个值匹配。 - 不匹配的来源被拒绝
403.
备注
- 使用
POST /mcp用于流式传输http请求。 - 这个启动器故意保持小范围(
tools仅)。
添加新工具
工具分为以下模块 tools/ 并已注册 @register_tool(...).
- 在下创建新文件
tools/(例如:tools/echo.py). - 定义
name,description,以及input_schema. - 返回MCP工具输出
content可选structuredContent. - 将模块导入
tools/__init__.py因此,注册在启动时运行。
例子:
from typing import Any
from tools.registry import register_tool
@register_tool(
name="echo",
description="Echo a string.",
input_schema={
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
"additionalProperties": False,
},
)
def echo(arguments: dict[str, Any]) -> dict[str, Any]:
text = arguments["text"]
return {
"content": [{"type": "text", "text": text}],
"structuredContent": {"text": text},
"isError": False,
}
无需更改 server.py 当通过此注册表流添加工具时。