
FastMCP å ¥é (2) - FastMCPãµãŒã
ãFastMCPãã®ããµãŒããã«ã€ããŠãŸãšããŸããã
åå
1. FastMCPãµãŒã
ãFastMCPãµãŒããã¯ãFastMCPã¢ããªã±ãŒã·ã§ã³ã®äžå¿ãšãªãã¯ã©ã¹ã§ãã¢ããªã±ãŒã·ã§ã³ã®ããŒã«ããªãœãŒã¹ãããã³ããã®ã¡ã€ã³ã³ã³ãããšããŠæ©èœãããMCPã¯ã©ã€ã¢ã³ãããšã®éä¿¡ã管çããŸãã
2. ãµãŒãã®äœæ
ãµãŒãã®ã€ã³ã¹ã¿ã³ã¹ã®äœææé ã¯ã次ã®ãšããã§ãã
éåžžã¯ãã¯ã©ã€ã¢ã³ãã¢ããªã±ãŒã·ã§ã³ããã°ã§ãµãŒããèå¥ã§ããããã«ããµãŒãã«ååãä»ããŸãã
from fastmcp import FastMCP
# åºæ¬çãªãµãŒãã€ã³ã¹ã¿ã³ã¹ãäœæ
mcp = FastMCP(name="MyAssistantServer")
# ãµãŒããšã®ããåãæ¹æ³ã«é¢ããæç€ºã远å ããããšãã§ãã
mcp_with_instructions = FastMCP(
name="HelpfulAssistant",
instructions="ãã®ãµãŒãã¯ããŒã¿åæããŒã«ãæäŸããŸããæ°å€ããŒã¿ãåæããã«ã¯ãget_average() ãåŒã³åºããŸãã"
)FastMCPã®ã³ã³ã¹ãã©ã¯ã¿ã®åŒæ°ã¯ã次ã®ãšããã§ãã
ã»name : (ãªãã·ã§ã³) ãµãŒãã®ååãããã©ã«ãã¯ãFastMCPãã
ã»instructions: (ãªãã·ã§ã³) ãµãŒããšã®ããåãæ¹æ³ã®èª¬æã
ã»lifespan: (ãªãã·ã§ã³) ãµãŒãã®èµ·åããã³ã·ã£ããããŠã³ããžãã¯çšã®éåæã³ã³ããã¹ããããŒãžã£é¢æ°ã
ã»tags: (ãªãã·ã§ã³) ãµãŒãèªäœã«ã¿ã°ãä»ããæååã®ã»ããã
ã»**settingsServerSettings: 远å èšå®ã«å¯Ÿå¿ããããŒã¯ãŒãåŒæ°ã
3. ã³ã³ããŒãã³ã
ãFastMCPãµãŒããã¯ãããã€ãã®çš®é¡ã®ã³ã³ããŒãã³ããã¯ã©ã€ã¢ã³ãã«å ¬éããŸãã
3-1. ããŒã«
ãããŒã«ãã¯ãã¯ã©ã€ã¢ã³ããã¢ã¯ã·ã§ã³ãå®è¡ãããå€éšã·ã¹ãã ã«ã¢ã¯ã»ã¹ãããããããã«åŒã³åºãããšãã§ãã颿°ã§ãã
@mcp.tool()
def multiply(a: float, b: float) -> float:
"""2ã€ã®æ°å€ãæãåããã"""
return a * b詳ããã¯ããã¥ã¡ã³ããããŒã«ããåç §ããŠãã ããã
3-2. ãªãœãŒã¹
ããªãœãŒã¹ãã¯ãã¯ã©ã€ã¢ã³ããèªã¿åãããšãã§ããããŒã¿ãœãŒã¹ãå ¬éããŸãã
@mcp.resource("data://config")
def get_config() -> dict:
"""ã¢ããªã±ãŒã·ã§ã³æ§æãæäŸ"""
return {"theme": "dark", "version": "1.0"}詳ããã¯ããã¥ã¡ã³ãããªãœãŒã¹ãšãã³ãã¬ãŒãããåç §ããŠãã ããã
3-3. ãªãœãŒã¹ãã³ãã¬ãŒã
ããªãœãŒã¹ãã³ãã¬ãŒããã¯ãã¯ã©ã€ã¢ã³ããç¹å®ã®ããŒã¿ãèŠæ±ã§ããããã«ãããã©ã¡ãŒã¿åããããªãœãŒã¹ã§ãã
@mcp.resource("users://{user_id}/profile")
def get_user_profile(user_id: int) -> dict:
"""IDã§ãŠãŒã¶ãŒãããã¡ã€ã«ãååŸ"""
# URIå
ã® {user_id} ãæœåºããããã®é¢æ°ã«æž¡ããã
return {"id": user_id, "name": f"User {user_id}", "status": "active"}詳ããã¯ããã¥ã¡ã³ãããªãœãŒã¹ãšãã³ãã¬ãŒãããåç §ããŠãã ããã
3-4. ããã³ãã
ãããã³ãããã¯ãLLM ãã¬ã€ãããããã®åå©çšå¯èœãªã¡ãã»ãŒãžãã³ãã¬ãŒãã§ãã
@mcp.prompt()
def analyze_data(data_points: list[float]) -> str:
"""æ°å€ããŒã¿ã®åæãæ±ããããã³ãããäœæ"""
formatted_data = ", ".join(str(point) for point in data_points)
return f"ããŒã¿ãã€ã³ããåæããŠãã ãã: {formatted_data}"詳ããã¯ããã¥ã¡ã³ããããã³ããããåç §ããŠãã ããã
4. ãµãŒãã®å®è¡
ãFastMCPãµãŒããã¯ãã¯ã©ã€ã¢ã³ããšéä¿¡ããããã«ãã©ã³ã¹ããŒãã¡ã«ããºã ãå¿ èŠãšããŸããMCPãããã³ã«ã§ã¯ããµãŒãã¯éåžžãã¯ã©ã€ã¢ã³ããæ¥ç¶ããåå¥ã®ããã»ã¹ãšããŠå®è¡ãããŸãã
4-1. __main__ ãããã¯ãã¿ãŒã³
ãµãŒããå®è¡å¯èœã«ããæšæºçãªæ¹æ³ã¯ãif __name__ == "__main__": ãããã¯å ã« run() ãå«ããããšã§ãã
# my_server.py
from fastmcp import FastMCP
mcp = FastMCP(name="MyServer")
@mcp.tool()
def greet(name: str) -> str:
"""ãŠãŒã¶ãŒã®ååã§ãããã€"""
return f"Hello, {name}!"
if __name__ == "__main__":
# ãã®ã³ãŒãã¯ãã¡ã€ã«ãçŽæ¥å®è¡ãããå Žåã«ã®ã¿å®è¡ããã
# ããã©ã«ãèšå®ã§ã®åºæ¬å®è¡ïŒstdioãã©ã³ã¹ããŒãïŒ
mcp.run()
# ç¹å®ã®ãã©ã³ã¹ããŒããšãã©ã¡ãŒã¿ã®äœ¿çš
# mcp.run(transport="sse", host="127.0.0.1", port=9000)ãã®ãã¿ãŒã³ãéèŠãªçç±ã¯ã次ã®ãšããã§ãã
ã»ã¯ã©ã€ã¢ã³ãäºææ§
æšæºçãªMCPã¯ã©ã€ã¢ã³ã (Claude Desktop ãªã©) ã¯ãpython my_server.py ã§ãµãŒããã¡ã€ã«ãçŽæ¥å®è¡ããããšãæ³å®ããŠããŸãã
ã»ããã»ã¹åé¢
åãµãŒãã¯ç¬èªã®ããã»ã¹ã§å®è¡ããããããã¯ã©ã€ã¢ã³ãã¯è€æ°ã®ãµãŒããç¬ç«ããŠç®¡çã§ããŸãã
ã»ã€ã³ããŒãã®å®å šæ§
__main__ãããã¯ã«ããããã¡ã€ã«ãä»ã®ã³ãŒãã«ãã£ãŠã€ã³ããŒããããéã«ãµãŒããå®è¡ãããã®ãé²ããŸãã
ãFastMCPãã®ãCLIãã䜿çšããå Žåããã®ãã¿ãŒã³ã¯æè¡çã«ã¯ãªãã·ã§ã³ã§ããããã¹ãŠã®ãMCPã¯ã©ã€ã¢ã³ãããšã®äºææ§ãæå€§éã«é«ããããã®ãã¹ããã©ã¯ãã£ã¹ãšèããããŠããŸãã
4-2. ãã©ã³ã¹ããŒããªãã·ã§ã³
ãFastMCPãã¯2ã€ã®ãã©ã³ã¹ããŒãã¡ã«ããºã ããµããŒãããŠããŸãã
ã»STDIO ãã©ã³ã¹ããŒã (ããã©ã«ã)
æšæºå
¥åºå (STDIO) ãã©ã³ã¹ããŒãã¯ãããã©ã«ãã§ãããæãäºææ§ã®é«ããªãã·ã§ã³ã§ãã
# stdioã§å®è¡ (ããã©ã«ã)
mcp.run() # ãŸãã¯æç€ºçã«: mcp.run(transport="stdio")ã»ã¯ã©ã€ã¢ã³ãã¯ã»ãã·ã§ã³ããšã«æ°ãããµãŒãããã»ã¹ãéå§ããŸãã
ã»éä¿¡ã¯æšæºå ¥åºåã¹ããªãŒã ãä»ããŠè¡ãããŸãã
ã»ã¯ã©ã€ã¢ã³ããåæããããšããµãŒãããã»ã¹ã¯çµäºããŸãã
ã»åäŒè©±ã«ç¬èªã®ãµãŒãã€ã³ã¹ã¿ã³ã¹ãå²ãåœãŠããããClaude Desktopããªã©ã®ããŒã«ãšã®çµ±åã«æé©ã§ãã
ã»SSEãã©ã³ã¹ããŒã (Server-Sent Events)
è€æ°ã®ã¯ã©ã€ã¢ã³ãã«ãµãŒãã¹ãæäŸããé·æé皌åãµãŒãåãã«ãFastMCPã¯SSEããµããŒãããŠããŸãã
# ããã©ã«ãã®ãã¹ã/ããŒã (0.0.0.0:8000) ã§SSEã䜿çšããŠå®è¡
mcp.run(transport="sse")ã»ãµãŒãã¯æ°žç¶çãªWebãµãŒããšããŠåäœããŸãã
ã»è€æ°ã®ã¯ã©ã€ã¢ã³ããåæã«æ¥ç¶ã§ããŸãã
ã»ãµãŒãã¯æç€ºçã«çµäºããããŸã§åäœãç¶ããŸãã
ã»ãµãŒãã¹ãžã®ãªã¢ãŒãã¢ã¯ã»ã¹ã«æé©ã§ãã
ãµãŒãã®å®è¡æã«ããã©ã³ã¹ããŒããã©ã¡ãŒã¿ãçŽæ¥èšå®ã§ããŸãã
# ç¹å®ã®ãã©ã¡ãŒã¿ã§èšå®
mcp.run(
transport="sse",
host="127.0.0.1", # Override default host
port=8888, # Override default port
log_level="debug" # Set logging level
)
# åããã©ã¡ãŒã¿ã§éåæçã«å®è¡
import asyncio
asyncio.run(
mcp.run_sse_async(
host="127.0.0.1",
port=8888,
log_level="debug"
)
)run() ãŸã㯠run_sse_async() ã«æž¡ããããã©ã³ã¹ããŒããã©ã¡ãŒã¿ã¯ãFastMCP ã€ã³ã¹ã¿ã³ã¹ã®äœææã«å®çŸ©ãããèšå®ãäžæžãããŸããSSEãã©ã³ã¹ããŒãã§æãäžè¬çãªãã©ã¡ãŒã¿ã¯ä»¥äžã®ãšããã§ãã
ã»host : ãã€ã³ãå ã®ãã¹ã (ããã©ã«ã : "0.0.0.0")
ã»port : ãã€ã³ãå ã®ããŒã (ããã©ã«ã : 8000)
ã»log_level : ãã°ã¬ãã« (ããã©ã«ã : "INFO")
ã»é«åºŠãªãã©ã³ã¹ããŒãæ§æ
FastMCP ã® run() ã¯ãå
éšçã«ã¯ããã©ã³ã¹ããŒãåºæã®å®è¡ã¡ãœããã«æž¡ãããä»»æã®ããŒã¯ãŒãåŒæ° (**transport_kwargs) ãåãå
¥ããŸãã
# SSEãã©ã³ã¹ããŒãã®å Žåãkwargsã¯run_sse_async()ã«æž¡ããã
mcp.run(transport="sse", **transport_kwargs)
# stdioãã©ã³ã¹ããŒãã®å Žåãkwargsã¯run_stdio_async()ã«æž¡ããã
mcp.run(transport="stdio", **transport_kwargs)å°æ¥çã«è¿œå ããããã©ã³ã¹ããŒãåºæã®ãªãã·ã§ã³ã¯ãã³ãŒãã倿Žããããšãªããåãã€ã³ã¿ãŒãã§ãŒã¹ããèªåçã«å©çšã§ããããã«ãªããŸãã
ã»FastMCP CLIã®äœ¿çš
FastMCP CLI ã¯ããµãŒããå®è¡ããããã®äŸ¿å©ãªæ¹æ³ãæäŸããŸãã
# ãµãŒããå®è¡ (ããã©ã«ãã¯stdioãã©ã³ã¹ããŒã)
fastmcp run my_server.py:mcp
# ãã©ã³ã¹ããŒããæç€ºçã«æå®
fastmcp run my_server.py:mcp --transport sse
# ãã¹ããšããŒãã§SSEãã©ã³ã¹ããŒããæ§æ
fastmcp run my_server.py:mcp --transport sse --host 127.0.0.1 --port 8888
# ãã°ã¬ãã«ä»ã
fastmcp run my_server.py:mcp --transport sse --log-level DEBUGCLI ã¯ãã¡ã€ã«å ã® FastMCP ãµãŒã ãªããžã§ã¯ããåçã«æ€çŽ¢ããŠå®è¡ã§ããŸãããif __name__ == "__main__": ãããã¯ãå«ãããšããã¹ãŠã®ã¯ã©ã€ã¢ã³ããšã®äºææ§ã確ä¿ãããŸãã
5. ã³ã³ããŒãžã³ã°ãµãŒã
FastMCPã¯ãimport_server (éçã³ããŒ) ãšmount (ã©ã€ããªã³ã¯) ã䜿çšããŠè€æ°ã®ãµãŒããçµ±åããæ©èœããµããŒãããŠããŸããããã«ãããå€§èŠæš¡ãªã¢ããªã±ãŒã·ã§ã³ãã¢ãžã¥ãŒã«åã³ã³ããŒãã³ãã«ãŸãšããããæ¢åã®ãµãŒããåå©çšãããããããšãå¯èœã«ãªããŸãã
詳现ããã¹ããã©ã¯ãã£ã¹ãããã³äŸã«ã€ããŠã¯ããµãŒãæ§æã¬ã€ããåç §ããŠãã ããã
# äŸ: ãµããµãŒãã®ã€ã³ããŒã
from fastmcp import FastMCP
import asyncio
main = FastMCP(name="Main")
sub = FastMCP(name="Sub")
@sub.tool()
def hello():
return "hi"
main.mount("sub", sub)6. ãããã·ãµãŒã
FastMCPã¯ãFastMCP.from_clientã䜿çšããããšã§ãä»»æã®MCPãµãŒã (ããŒã«ã«ãŸãã¯ãªã¢ãŒã) ã®ãããã·ãšããŠåäœãããã©ã³ã¹ããŒããããªããžããããæ¢åã®ãµãŒãã«ããã³ããšã³ãã远å ãããã§ããŸããäŸãã°ããªã¢ãŒãSSEãµãŒããstdioçµç±ã§ããŒã«ã«ã«å ¬éãããããã®éãè¡ã£ããã§ããŸãã
詳ããã¯ãããã·ãµãŒãã¬ã€ããåç §ããŠãã ããã
from fastmcp import FastMCP, Client
backend = Client("http://example.com/mcp/sse")
proxy = FastMCP.from_client(backend, name="ProxyServer")
# ä»ã®FastMCPãµãŒããšåæ§ã«ãããã·ã䜿çš7. ãµãŒãã®æ§æ
ãã©ã³ã¹ããŒãèšå® (SSEã®hostãport) ãéè€ã³ã³ããŒãã³ãã®åŠçæ¹æ³ãšãã£ããµãŒãã®åäœã¯ãServerSettingsã§èšå®ã§ããŸãããããã®èšå®ã¯ãFastMCPã®åæåæã«æž¡ãããç°å¢å€æ°ïŒFASTMCP_SERVER_ã§å§ãŸãïŒã§èšå®ãããã.envããèªã¿èŸŒãããšãã§ããŸãã
from fastmcp import FastMCP
# åæåäžã«èšå®
mcp = FastMCP(
name="ConfiguredServer",
port=8080, # ServerSettingsã«çŽæ¥ããã
on_duplicate_tools="error" # éè€åŠçãèšå®
)
# èšå®ã¯mcp.settingsããã¢ã¯ã»ã¹ã§ãã
print(mcp.settings.port) # åºå: 8080
print(mcp.settings.on_duplicate_tools) # åºå: "error"äž»èŠãªèšå®ãªãã·ã§ã³ã¯ã次ã®ãšããã§ãã
ã»host : SSEãã©ã³ã¹ããŒãã®ãã¹ãã¢ãã¬ã¹ (ããã©ã«ã : â0.0.0.0â)
ã»port : SSEãã©ã³ã¹ããŒãã®ããŒãçªå· (ããã©ã«ã : 8000)
ã»log_level : ãã°ã¬ãã« (ããã©ã«ã : "INFO")
ã»on_duplicate_tools : ããŒã«ç»é²ã®éè€ã®åŠçæ¹æ³
ã»on_duplicate_resources : ãªãœãŒã¹ç»é²ã®éè€ã®åŠçæ¹æ³
ã»on_duplicate_prompts : ããã³ããç»é²ã®éè€ã®åŠçæ¹æ³
ãããã¯ãã¹ãŠãFastMCPã€ã³ã¹ã¿ã³ã¹ã®äœææã«ãã©ã¡ãŒã¿ãšããŠçŽæ¥èšå®ã§ããŸãã
8. èªèšŒ
FastMCP ã¯ãMCP ãããã³ã«ãã OAuth 2.0 èªèšŒã®ãµããŒããç¶æ¿ãããµãŒããèªèšŒã®èåŸã§ããŒã«ãšãªãœãŒã¹ãä¿è·ã§ããããã«ããŸãã
8-1. OAuth 2.0 ãµããŒã
mcp.server.auth ã¢ãžã¥ãŒã«ã¯ãOAuthServerProvider ãããã³ã«ã®å®è£ ãæäŸããããšã§ããµãŒãã䜿çšã§ãã OAuth 2.0 ãµãŒãã€ã³ã¿ãŒãã§ãŒã¹ãå®è£ ããŸãã
from fastmcp import FastMCP
from mcp.server.auth.settings import (
RevocationOptions,
ClientRegistrationOptions,
AuthSettings,
)
# èªèšŒä»ããµãŒããäœæ
mcp = FastMCP(
name="SecureApp",
auth_provider=MyOAuthServerProvider(),
auth=AuthSettings(
issuer_url="https://myapp.com",
revocation_options=RevocationOptions(
enabled=True,
),
client_registration_options=ClientRegistrationOptions(
enabled=True,
valid_scopes=["myscope", "myotherscope"],
default_scopes=["myscope"],
),
required_scopes=["myscope"],
),
)