MarkTechPost@AI 09月02日
使用Scalekit为MCP服务器实现OAuth 2.1认证
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本教程详细介绍了如何为MCP服务器一步步实现OAuth 2.1认证。文章以构建一个简单的金融情绪分析服务器为例,并使用Scalekit工具简化OAuth配置。通过暴露元数据端点URL和添加授权中间件,Scalekit能够自动处理复杂的OAuth流程,包括令牌生成、刷新和验证。设置完成后,MCP服务器即可无缝处理经过身份验证的请求。教程还涵盖了依赖项设置(Alpha Vantage API、Node.js、Python)、Scalekit账户创建与配置、API凭证获取以及.env和config.py文件的配置,并提供了完整的代码示例和运行指南。

🔐 **OAuth 2.1认证的实现**:本教程详细阐述了如何利用Scalekit库为MCP服务器实现OAuth 2.1协议,简化了身份验证流程。Scalekit负责处理复杂的OAuth 2.1流程,包括令牌生成、刷新和验证,使得开发者无需手动管理这些过程,从而加速了安全认证的集成。

📊 **金融情绪分析服务器构建**:文章以一个实际的金融情绪分析服务器为例,演示了如何集成Alpha Vantage API来获取股票新闻的情绪数据。通过解析API返回的新闻标题、摘要、来源和发布时间,为用户提供及时的市场洞察。

⚙️ **Scalekit配置与集成**:教程指导用户完成Scalekit的注册、权限设置(如`news:read`)、MCP服务器的添加与配置,并获取必要的API凭证(Client ID, Secret Key, Environment URL)。这些配置信息被整合到`.env`文件中,并通过`config.py`加载,为服务器的认证机制提供支持。

🛡️ **安全授权中间件**:文章详细介绍了如何创建一个`AuthMiddleware`,该中间件作为授权层,在处理请求前验证Bearer令牌的有效性。它能够识别并放行公共路径(如元数据端点),并对携带无效或缺失令牌的请求返回401 Unauthorized错误,确保只有经过身份验证的请求才能访问受保护的资源。

🚀 **服务器部署与测试**:最后,教程展示了如何设置FastAPI应用,集成MCP服务器和`AuthMiddleware`,并通过`uvicorn`运行。同时,提供了使用`@modelcontextprotocol/inspector`工具进行端到端测试的步骤,包括如何提供有效的Bearer令牌以成功连接和调用服务器工具。

In this tutorial, we’ll explore how to implement OAuth 2.1 for MCP servers step by step. To keep things practical, we’ll build a simple finance sentiment analysis server and secure it using Scalekit, a tool that makes setting up OAuth both faster and easier.

With Scalekit, all we need to do is expose a metadata endpoint URL for MCP clients to discover the server and add authorization middleware for secure token-based authentication. Scalekit handles all the complex OAuth 2.1 flows behind the scenes, so you don’t need to manually implement or manage token generation, refresh, or validation. Once this setup is complete, your MCP server is ready to handle authenticated requests seamlessly. Check out the FULL CODES here.

Setting up dependencies

Alpha Vantage API

To fetch stock news sentiment, we’ll use the Alpha Vantage API. To get a free API key:

Node JS

To run the MCP Inspector for testing our application, we need Node.js installed.

Python Dependencies

pip install fastapi fastmcp mcp scalekit-sdk-python

Scalekit

To start using Scalekit, follow these steps:

Create Your Scalekit Account

Set Up Permissions

Permission Name: news:read

Description: Use Alpha Vantage to get Stock Sentiment

Permissions in Scalekit are used to define and manage scopes that control what features or resources your application can access. For example, the news:read permission allows your MCP server to access stock sentiment data from Alpha Vantage, while other permissions could be created to gate additional features or APIs within your application.

Add Your MCP Server

Server Name: Any name you prefer.

Resource Identifier: A unique identifier for your MCP server. This value is included in the aud claim of access tokens, helping the server validate requests.

For local testing, set it as:

http://localhost:10000/mcp/

When using FastMCP, the /mcp path is automatically added to the endpoint. Make sure to include the trailing slash at the end to avoid configuration issues. Check out the FULL CODES here.

Set the scope to the permission you just created: news:read

Once the server is created, Scalekit will generate your resource metadata. Be sure to note down the MCP Server Identifier (found next to the server name, e.g., res_88056357768398086), as you’ll need it later.

Resource Metadata Example

Your metadata will look similar to this (but unique for your account):

Metadata Endpoint URL:

/.well-known/oauth-protected-resource/mcp

Resource Metadata JSON:

{  "authorization_servers": [    "https://zapp.scalekit.dev/resources/res_88056357768398086"  ],  "bearer_methods_supported": ["header"],  "resource": "http://localhost:10000/mcp/",  "resource_documentation": "http://localhost:10000/mcp/docs",  "scopes_supported": ["news:read"]}

Get API Credentials

Store these values securely — we’ll need them later for configuration.

.env

We will now create a .env file with the following variables

ALPHA_VANTAGE_API_KEY=<YOUR_ALPHA_VANTAGE_API_KEY>METADATA_JSON_RESPONSE=<YOUR_METADATA_JSON_RESPONSE>SCALEKIT_ENVIRONMENT_URL=<YOUR_SCALEKIT_ENVIRONMENT_URL>SCALEKIT_CLIENT_ID=<YOUR_SCALEKIT_CLIENT_ID>SCALEKIT_CLIENT_SECRET=<YOUR_SCALEKIT_CLIENT_SECRET>SCALEKIT_RESOURCE_METADATA_URL=<YOUR_SCALEKIT_RESOURCE_METADATA_URL>SCALEKIT_AUTHORIZATION_SERVERS=<YOUR_SCALEKIT_AUTHORIZATION_SERVERS>SCALEKIT_AUDIENCE_NAME=<YOUR_SCALEKIT_AUDIENCE_NAME>SCALEKIT_RESOUCE_NAME=<YOUR_SCALEKIT_RESOURCE_NAME>SCALEKIT_RESOUCE_DOCS_URL=<YOUR_SCALEKIT_RESOURCE_DOCS_URL>

ALPHA_VANTAGE_API_KEY

Your personal API key from Alpha Vantage, used to fetch stock sentiment data.

METADATA_JSON_RESPONSE

The JSON response generated by Scalekit when you configure your MCP server.

It contains details like authorization servers, supported scopes, and documentation URLs.

SCALEKIT_ENVIRONMENT_URL

The environment URL under the Settings section.

SCALEKIT_CLIENT_ID

The client ID mentioned under the Settings section.

SCALEKIT_CLIENT_SECRET

The secret key you generate under Settings → API Credentials.

SCALEKIT_RESOURCE_METADATA_URL

The URL exposed by your MCP server for metadata requests.

Example:

http://localhost:10000/.well-known/oauth-protected-resource/mcp

SCALEKIT_AUTHORIZATION_SERVERS

The URL pointing to the MCP Server Identifier issued by Scalekit.

Example:

https://<your-subdomain>.scalekit.dev/resources/res_***************

You can find the subdomain from the resource metadata JSON

SCALEKIT_AUDIENCE_NAME

The audience (aud) claim used in access tokens to validate requests. Check out the FULL CODES here.

http://localhost:10000/mcp/

SCALEKIT_RESOUCE_NAME

The resource name for your MCP server. In most cases, this is the same as SCALEKIT_AUDIENCE_NAME. Check out the FULL CODES here.

SCALEKIT_RESOUCE_DOCS_URL

The URL where your MCP server’s documentation is hosted.

Example:

http://localhost:10000/mcp/docs

Configuration File (config.py) 

We will first create a config file to load all the environment variables which will be used later. Check out the FULL CODES here.

import osfrom dotenv import load_dotenvload_dotenv()class Settings():    ALPHA_VANTAGE_API_KEY = os.environ.get('ALPHA_VANTAGE_API_KEY')    METADATA_JSON_RESPONSE = os.environ.get('METADATA_JSON_RESPONSE')    SCALEKIT_ENVIRONMENT_URL = os.environ.get('SCALEKIT_ENVIRONMENT_URL')    SCALEKIT_CLIENT_ID = os.environ.get('SCALEKIT_CLIENT_ID')    SCALEKIT_CLIENT_SECRET = os.environ.get('SCALEKIT_CLIENT_SECRET')    SCALEKIT_RESOURCE_METADATA_URL = os.environ.get('SCALEKIT_RESOURCE_METADATA_URL')    SCALEKIT_AUTHORIZATION_SERVERS = os.environ.get('SCALEKIT_AUTHORIZATION_SERVERS')    SCALEKIT_AUDIENCE_NAME = os.environ.get('SCALEKIT_AUDIENCE_NAME')    SCALEKIT_RESOUCE_NAME = os.environ.get('SCALEKIT_RESOUCE_NAME')    SCALEKIT_RESOUCE_DOCS_URL = os.environ.get('SCALEKIT_RESOUCE_DOCS_URL')    PORT = 10000    settings = Settings()

Stock Sentiment Logic (finance.py)

This code block fetches real-time news sentiment data for a given stock ticker using the Alpha Vantage API. It retrieves the top three recent articles, summarizing their title, summary, source, and publication time for quick insights. Check out the FULL CODES here.

from mcp.server.fastmcp import FastMCPfrom typing import Anyimport osimport httpxfrom typing import Dict, Listfrom config import settings# Create an MCP servermcp = FastMCP("finance-news")BASE_URL = "https://www.alphavantage.co/query"async def call_alpha_vantage(endpoint: str, params: dict[str, Any]) -> dict[str, Any] | None:    """Generic async caller to Alpha Vantage."""    params["apikey"] = settings.ALPHA_VANTAGE_API_KEY    params["function"] = endpoint    async with httpx.AsyncClient() as client:        try:            response = await client.get(BASE_URL, params=params, timeout=30.0)            response.raise_for_status()            return response.json()        except Exception:            return None@mcp.tool()async def get_news_sentiment(ticker: str) -> str:    """Get news sentiment data for a stock ticker.    Args:        ticker: Stock ticker symbol (e.g., MSFT, AAPL)    """    data = await call_alpha_vantage("NEWS_SENTIMENT", {"tickers": ticker.upper()})    if not data or "feed" not in data:        return "Couldn't retrieve news sentiment."    articles = data["feed"][:3]    result = []    for item in articles:        result.append(f"""     {item['title']}    Summary: {item['summary']}    Source: {item['source']} | Published: {item['time_published']}    """)    return "n---n".join(result)

Authorization Middleware

This middleware acts as an authorization layer for your MCP server, ensuring that only authenticated requests are processed. It uses the ScaleKit client to validate access tokens on every incoming request. When a request comes in, the middleware first checks if the path is public, such as metadata endpoints under /.well-known/

If the request isn’t for a public path, it looks for an Authorization header with a valid Bearer token. The token is then validated using ScaleKit. If the token is missing, invalid, or expired, the middleware immediately responds with a 401 Unauthorized error and a structured error message. Check out the FULL CODES here.

If the token is valid, the request is passed along to the next layer of the application. Additionally, logging is integrated throughout the process to capture key events, making it easier to debug and audit authentication flows.

Finally, this middleware will be imported and added to the server file to protect all secure endpoints. Check out the FULL CODES here.

import jsonimport loggingfrom fastapi import HTTPException, Requestfrom fastapi.security import HTTPBearerfrom fastapi.responses import JSONResponsefrom scalekit import ScalekitClientfrom starlette.middleware.base import BaseHTTPMiddlewarefrom config import settings# Configure logginglogging.basicConfig(    level=logging.INFO,    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')logger = logging.getLogger(__name__)# Security scheme for Bearer tokensecurity = HTTPBearer()# Initialize ScaleKit clientscalekit_client = ScalekitClient(    settings.SCALEKIT_ENVIRONMENT_URL,    settings.SCALEKIT_CLIENT_ID,    settings.SCALEKIT_CLIENT_SECRET)# Authentication middlewareclass AuthMiddleware(BaseHTTPMiddleware):    async def dispatch(self, request: Request, call_next):        if request.url.path.startswith("/.well-known/"):            return await call_next(request)        try:            auth_header = request.headers.get("Authorization")            if not auth_header or not auth_header.startswith("Bearer "):                raise HTTPException(status_code=401, detail="Missing or invalid authorization header")            token = auth_header.split(" ")[1]            request_body = await request.body()                        # Parse JSON from bytes            try:                request_data = json.loads(request_body.decode('utf-8'))            except (json.JSONDecodeError, UnicodeDecodeError):                request_data = {}                        try:                scalekit_client.validate_access_token(token)                            except Exception as e:                raise HTTPException(status_code=401, detail="Token validation failed")        except HTTPException as e:            return JSONResponse(                status_code=e.status_code,                content={"error": "unauthorized" if e.status_code == 401 else "forbidden", "error_description": e.detail},                headers={                    "WWW-Authenticate": f'Bearer realm="OAuth", resource_metadata="{settings.SCALEKIT_RESOURCE_METADATA_URL}"'                }            )        return await call_next(request)

MCP Server (server.py)

This script sets up a FastAPI application integrated with an MCP server for stock news sentiment analysis. It begins by importing the necessary libraries, including FastAPI, CORS middleware, and a custom authentication middleware. Check out the FULL CODES here.

The application lifecycle is managed through a combined lifespan context using an asynchronous context manager, ensuring that the finance_news_server.session_manager, which is essentially the stock sentiment logic we created, runs smoothly during the app’s runtime. CORS middleware is configured to allow cross-origin requests, which is useful during development but should be restricted in production environments.

A new endpoint, /.well-known/oauth-protected-resource/mcp, is added to serve metadata for OAuth 2.1 protected resource discovery. This endpoint provides important details such as supported authorization servers, bearer token methods, resource name, documentation URL, and supported scopes — in this case, mcp:tools:news:read.

The MCP server is created using the finance_news_server.streamable_http_app() function and mounted at the root path /, making the core MCP functionalities accessible through the main app. Authentication is enforced by integrating the AuthMiddleware, and the script ensures that this middleware is properly added to the server file. 

Finally, the main() function runs the application using uvicorn, with logging enabled at the debug level, binding the server to localhost on the configured port. Check out the FULL CODES here.

import contextlibimport uvicornfrom fastapi import FastAPIfrom fastapi.middleware.cors import CORSMiddlewareimport jsonfrom auth import AuthMiddlewarefrom config import settingsfrom finance import mcp as finance_news_server# Create a combined lifespan to manage the MCP session manager@contextlib.asynccontextmanagerasync def lifespan(app: FastAPI):    async with finance_news_server.session_manager.run():        yieldapp = FastAPI(lifespan=lifespan)# Add CORS middlewareapp.add_middleware(    CORSMiddleware,    allow_origins=["*"],  # In production, specify your actual origins    allow_credentials=True,    allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],    allow_headers=["*"],)# MCP well-known endpoint@app.get("/.well-known/oauth-protected-resource/mcp")async def oauth_protected_resource_metadata():    """    OAuth 2.0 Protected Resource Metadata endpoint for MCP client discovery.    Required by the MCP specification for authorization server discovery.    """    return {        "authorization_servers": [settings.SCALEKIT_AUTHORIZATION_SERVERS],        "bearer_methods_supported": ["header"],        "resource": settings.SCALEKIT_RESOURCE_NAME,        "resource_documentation": settings.SCALEKIT_RESOURCE_DOCS_URL,        "scopes_supported": [          "mcp:tools:news:read"        ],    }# Create and mount the MCP server with authenticationmcp_server = finance_news_server.streamable_http_app()app.add_middleware(AuthMiddleware)app.mount("/", mcp_server)def main():    """Main entry point for the MCP server."""    uvicorn.run(app, host="localhost", port=settings.PORT, log_level="debug")if __name__ == "__main__":    main()

Running the Server

To run the server, execute python server.py, which will start the application on localhost:10000. To test the setup, open another terminal and run:

npx @modelcontextprotocol/inspector

Once the MCP Inspector is running, enter http://localhost:10000/mcp as the server URL. If you attempt to connect without providing valid credentials, you will encounter the following error:

Connection Error: Check if your MCP Server is running and if the proxy token is correctly configured.

Now, provide the Bearer token using the secret ID you generated in Scalekit. Once entered, you will be successfully authenticated and can start making tool calls.


Check out the FULL CODES here. Feel free to check out our GitHub Page for Tutorials, Codes and Notebooks. Also, feel free to follow us on Twitter and don’t forget to join our 100k+ ML SubReddit and Subscribe to our Newsletter.

The post Implementing OAuth 2.1 for MCP Servers with Scalekit: A Step-by-Step Coding Tutorial appeared first on MarkTechPost.

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

OAuth 2.1 MCP Server Scalekit API认证 金融情绪分析 FastAPI Alpha Vantage Python Node.js 安全集成
相关文章