๐Ÿฝ๏ธ MCP ๅฎŒๅ…จๆŒ‡ๅ—๏ผšAI ็š„"ไธ‡่ƒฝๆœๅŠกๅ‘˜"ๅ่ฎฎ

12 ้˜…่ฏป16ๅˆ†้’Ÿ

็ฌฌไธ€็ซ ๏ผšๆ•…ไบ‹ๅผ€ๅง‹ โ€”โ€” ไธ€ๅฎถ"ๆฒกๆœ‰่œๅ•"็š„้คๅŽ…

ๆƒณ่ฑกไฝ ๅผ€ไบ†ไธ€ๅฎถ้คๅŽ…๏ผŒ่ฏทไบ†ไธ€ไธช่ถ…็บง่ชๆ˜Žไฝ†ไป€ไนˆ้ƒฝไธ่ฎฐๅพ—็š„ๅŽจๅธˆ๏ผˆ่ฟ™ๅฐฑๆ˜ฏ AI ๆจกๅž‹๏ผ‰ใ€‚

ๅŽจๅธˆ๏ผšโ€œไฝ ่ฆๆˆ‘ๅšไป€ไนˆ่œ๏ผŸโ€
ไฝ ๏ผšโ€œๅšไธช็บข็ƒง่‚‰ใ€‚โ€
ๅŽจๅธˆ๏ผšโ€œ็บข็ƒง่‚‰ๆ˜ฏไป€ไนˆ๏ผŸ็”จไป€ไนˆๆๆ–™๏ผŸๆ€Žไนˆๅš๏ผŸๆˆ‘ๅ…จไธ็Ÿฅ้“ใ€‚โ€

ๅŽจๅธˆๅพˆ่ชๆ˜Ž๏ผŒๅญฆไป€ไนˆ้ƒฝๅฟซ๏ผŒไฝ†ไป–ๅฎŒๅ…จไธไบ†่งฃๅค–้ข็š„ไธ–็•Œย โ€”โ€” ไธ็Ÿฅ้“ไฝ ็š„ๅ†ฐ็ฎฑ้‡Œๆœ‰ไป€ไนˆใ€ไธ็Ÿฅ้“ๆ€ŽไนˆๆŸฅ่œ่ฐฑใ€ไธ็Ÿฅ้“ๆ€Žไนˆๅผ€็ซใ€‚

ไปฅๅ‰๏ผŒๆฏไธช้คๅŽ…่€ๆฟ้ƒฝๅ‘ๆ˜Ž่‡ชๅทฑ็š„ๆ–นๆณ•ๆฅ่ทŸๅŽจๅธˆๆฒŸ้€š๏ผš

  • ๅผ ๅฎถ็”จ็บธๆกไผ ้€’
  • ๆŽๅฎถ็”จๅฏน่ฎฒๆœบๅ–Š่ฏ
  • ็Ž‹ๅฎถ่‡ชๅทฑ้€ ไบ†ไธ€ๅฅ—ๆ‰‹่ฏญ

็ป“ๆžœๅฐฑๆ˜ฏ๏ผšๆฏไธชๅŽจๅธˆ็š„"ๅค–ๆŒ‚"้ƒฝไธ้€š็”จ๏ผŒๆขไธช้คๅŽ…ๅฐฑๅพ—้‡ๆ–ฐๅญฆไธ€ๅฅ—ใ€‚

็›ดๅˆฐๆœ‰ไธ€ๅคฉ๏ผŒๆ•ดไธช้ค้ฅฎ็•Œ็ปŸไธ€ไบ†ไธ€ไธชๅ่ฎฎ โ€”โ€”ย MCP๏ผˆModel Context Protocol๏ผŒๆจกๅž‹ไธŠไธ‹ๆ–‡ๅ่ฎฎ๏ผ‰ ใ€‚

็ฌฌไบŒ็ซ ๏ผšๆ ธๅฟƒๆžถๆž„ โ€”โ€” ๅ››ไธช่ง’่‰ฒๅ„ๅธๅ…ถ่Œ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                        ไฝ ็š„็”ต่„‘/ๆ‰‹ๆœบ                          โ”‚
โ”‚                                                             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                           โ”‚
โ”‚  โ”‚   Host ๅฎฟไธป   โ”‚  โ† ๆฏ”ๅฆ‚ Claude Desktopใ€VS Code ๆ’ไปถ      โ”‚
โ”‚  โ”‚  (้คๅŽ…ๅคงๅ ‚)   โ”‚                                           โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                           โ”‚
โ”‚         โ”‚ 1ๅฏน1 ๅˆ›ๅปบ                                           โ”‚
โ”‚         โ–ผ                                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                      โ”‚
โ”‚  โ”‚ Client ๅฎขๆˆท็ซฏ โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚ Server ๆœๅŠก็ซฏ โ”‚  โ† ๅคฉๆฐ”ๅŽๅŽจ          โ”‚
โ”‚  โ”‚  (ๆœๅŠกๅ‘˜A)    โ”‚โ—€โ”€โ”€โ”€โ”€โ”‚  (ไธญ้คๅŽๅŽจ)   โ”‚                      โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                      โ”‚
โ”‚         โ”‚                                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                      โ”‚
โ”‚  โ”‚ Client ๅฎขๆˆท็ซฏ โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚ Server ๆœๅŠก็ซฏ โ”‚  โ† ๆ–‡ไปถๅŽๅŽจ          โ”‚
โ”‚  โ”‚  (ๆœๅŠกๅ‘˜B)    โ”‚โ—€โ”€โ”€โ”€โ”€โ”‚  (่ฅฟ้คๅŽๅŽจ)   โ”‚                      โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                      โ”‚
โ”‚         โ”‚                                                   โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                      โ”‚
โ”‚  โ”‚ Client ๅฎขๆˆท็ซฏ โ”‚โ”€โ”€โ”€โ”€โ–ถโ”‚ Server ๆœๅŠก็ซฏ โ”‚  โ† ๆ•ฐๆฎๅบ“ๅŽๅŽจ        โ”‚
โ”‚  โ”‚  (ๆœๅŠกๅ‘˜C)    โ”‚โ—€โ”€โ”€โ”€โ”€โ”‚  (็”œ็‚นๅŽๅŽจ)   โ”‚                      โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                      โ”‚
โ”‚                                                             โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿจ ็”จ้คๅŽ…ๆœฏ่ฏญ็†่งฃ

MCP ๆฆ‚ๅฟต้คๅŽ…ๆฏ”ๅ–ป็œŸๅฎž่ง’่‰ฒไธพไพ‹
Host้คๅŽ…ๅคงๅ ‚่ฟ่กŒ AI ็š„ไธป็จ‹ๅบClaude Desktopใ€Cursor
ClientๆœๅŠกๅ‘˜ๅ่ฎฎ็ฟป่ฏ‘ๅฎ˜๏ผˆHost ่‡ชๅŠจๅˆ›ๅปบ๏ผ‰ๆฏไธช Server ๅฏนๅบ”ไธ€ไธช Client
ServerๅŽๅŽจๆไพ›่ƒฝๅŠ›็š„็จ‹ๅบๅคฉๆฐ”ๆœๅŠกใ€ๆ–‡ไปถ็ณป็ปŸใ€ๆ•ฐๆฎๅบ“
ToolๅŽจๅธˆๆŠ€่ƒฝๆจกๅž‹ๅฏ่ฐƒ็”จ็š„ๅ‡ฝๆ•ฐget_weather()ใ€read_file()
Resource้ฃŸๆๅบ“ๆœๅŠกๅ™จๆšด้œฒ็š„ๆ•ฐๆฎๅคฉๆฐ”ๆ•ฐๆฎใ€ๆ–‡ไปถๅ†…ๅฎนใ€ๆ•ฐๆฎๅบ“่ฎฐๅฝ•
Promptๅฅ—้ค่œๅ•้ข„ๅฎšไน‰็š„ๆ็คบๆจกๆฟโ€œๅˆ†ๆžๅคฉๆฐ”ๅนถ็ป™ๅปบ่ฎฎโ€

ๅ…ณ้”ฎ่ง„ๅˆ™๏ผš

  • ไธ€ไธช Host ๅฏไปฅๆœ‰ๅคšไธชย Client
  • ไธ€ไธช Client ๅช่ฟžๆŽฅไธ€ไธชย Server๏ผˆไธ€ๅฏนไธ€๏ผ‰
  • Host ่ดŸ่ดฃ็ฎก็†ๆ‰€ๆœ‰ Client ็š„็”Ÿๅ‘ฝๅ‘จๆœŸ๏ผˆๅฏๅŠจใ€ๅ…ณ้—ญ๏ผ‰
  • Client ๅ’Œ Server ไน‹้—ด็”จย JSON-RPC 2.0ย ้€šไฟก๏ผˆๅฐฑๅƒๆœๅŠกๅ‘˜็”จๆ ‡ๅ‡†ๆ ผๅผๅ†™็‚น่œๅ•๏ผ‰

็ฌฌไธ‰็ซ ๏ผšไธ‰ๅคง่ƒฝๅŠ› โ€”โ€” ๅŽๅŽจ่ƒฝๅšไป€ไนˆ๏ผŸ

๐Ÿ”ง Tool๏ผˆๅทฅๅ…ท๏ผ‰โ€”โ€” ๅŽจๅธˆ็š„"ๅŠจๆ‰‹่ƒฝๅŠ›"

ๅทฅๅ…ทๅฐฑๆ˜ฏๆจกๅž‹ๅฏไปฅไธปๅŠจ่ฐƒ็”จ็š„ๅ‡ฝๆ•ฐใ€‚ๅฐฑๅƒๅŽจๅธˆ่ฏด๏ผšโ€œๆˆ‘่ฆ็‚’่œ๏ผŒๅธฎๆˆ‘ๅผ€็ซ๏ผโ€

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("kitchen-server")

@mcp.tool()
def stir_fry(ingredient: str, duration: int) -> str:
    """
    ็‚’่œๅทฅๅ…ท
    
    Args:
        ingredient: ้ฃŸๆๅ็งฐ
        duration: ็‚’ๅˆถๆ—ถ้—ด๏ผˆๅˆ†้’Ÿ๏ผ‰
    
    Returns:
        ็‚’่œ็ป“ๆžœๆ่ฟฐ
    """
    return f"็”จๅคง็ซ็ฟป็‚’{ingredient}๏ผŒ{duration}ๅˆ†้’ŸๅŽๅ‡บ้”…๏ผŒ้ฆ™ๆฐ”ๅ››ๆบข๏ผ"

@mcp.tool()
def check_fridge(item: str) -> str:
    """ๆฃ€ๆŸฅๅ†ฐ็ฎฑ้‡Œๆœ‰ๆฒกๆœ‰ๆŸไธช้ฃŸๆ"""
    fridge = ["้ธก่›‹", "่ฅฟ็บขๆŸฟ", "็‰›่‚‰", "่‘ฑๅงœ่’œ"]
    if item in fridge:
        return f"ๅ†ฐ็ฎฑ้‡Œๆœ‰{item}๏ผŒๆ–ฐ้ฒœๅบฆ่‰ฏๅฅฝ โœ“"
    return f"ๅ†ฐ็ฎฑ้‡Œๆฒกๆœ‰{item} โœ—"

ๆจกๅž‹็š„ๆ€่€ƒ่ฟ‡็จ‹๏ผš

็”จๆˆท: "ๅธฎๆˆ‘ๅšไธช่ฅฟ็บขๆŸฟ็‚’่›‹"
ๆจกๅž‹ๅ†…ๅฟƒ: ๆˆ‘้œ€่ฆ๏ผš
  1. ๅ…ˆ check_fridge("่ฅฟ็บขๆŸฟ") โ†’ "ๅ†ฐ็ฎฑ้‡Œๆœ‰่ฅฟ็บขๆŸฟ โœ“"
  2. ๅ† check_fridge("้ธก่›‹")   โ†’ "ๅ†ฐ็ฎฑ้‡Œๆœ‰้ธก่›‹ โœ“"  
  3. ็„ถๅŽ stir_fry("่ฅฟ็บขๆŸฟ้ธก่›‹", 5) โ†’ "็”จๅคง็ซ็ฟป็‚’..."
  4. ็ปผๅˆไปฅไธŠ็ป“ๆžœๅ›žๅค็”จๆˆท

๐Ÿ“ฆ Resource๏ผˆ่ต„ๆบ๏ผ‰โ€”โ€” ้ฃŸๆๅบ“

่ต„ๆบๆ˜ฏๆœๅŠกๅ™จๆšด้œฒ็š„้™ๆ€ๆˆ–ๅŠจๆ€ๆ•ฐๆฎใ€‚ๆจกๅž‹ไธ่ƒฝไฟฎๆ”น๏ผŒๅช่ƒฝ่ฏปๅ–ใ€‚

@mcp.resource("menu://today")  # URI ๆ ผๅผ็š„่ต„ๆบๆ ‡่ฏ†
def get_today_menu() -> str:
    """่Žทๅ–ไปŠๆ—ฅ่œๅ•"""
    return """
    ไปŠๆ—ฅ็‰น่‰ฒ่œ๏ผš
    1. ็บข็ƒง่‚‰ - ยฅ68
    2. ๆธ…่’ธ้ฒˆ้ฑผ - ยฅ88  
    3. ๅฎซไฟ้ธกไธ - ยฅ48
    """

@mcp.resource("recipe://{dish_name}")  # ๅธฆๅ‚ๆ•ฐ็š„่ต„ๆบ
def get_recipe(dish_name: str) -> str:
    """่Žทๅ–่œ่ฐฑ"""
    recipes = {
        "็บข็ƒง่‚‰": "ไบ”่Šฑ่‚‰500gใ€ๅ†ฐ็ณ–30gใ€้…ฑๆฒน2ๅ‹บใ€ๆ–™้…’1ๅ‹บ...",
        "ๅฎซไฟ้ธกไธ": "้ธก่ƒธ่‚‰300gใ€่Šฑ็”Ÿ็ฑณ50gใ€ๅนฒ่พฃๆค’10ไธช..."
    }
    return recipes.get(dish_name, "ๆš‚ๆ— ๆญค่œ่ฐฑ")

Tool ๅ’Œ Resource ็š„ๅŒบๅˆซ๏ผš

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  Tool๏ผˆๅทฅๅ…ท๏ผ‰                  Resource๏ผˆ่ต„ๆบ๏ผ‰        โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  ๐ŸŽฏ ๆจกๅž‹ไธปๅŠจ่ฐƒ็”จ              ๐Ÿ“– ๆจกๅž‹ๆŒ‰้œ€่ฏปๅ–           โ”‚
โ”‚  โšก ๆœ‰ๅ‰ฏไฝœ็”จ๏ผˆๆ”นๅ˜็Šถๆ€๏ผ‰        ๐Ÿ”’ ๅช่ฏป๏ผˆๆ— ๅ‰ฏไฝœ็”จ๏ผ‰       โ”‚
โ”‚  ๐Ÿ”ง ๆ‰ง่กŒๆ“ไฝœ                  ๐Ÿ“ฆ ๆไพ›ๆ•ฐๆฎ              โ”‚
โ”‚  ๐Ÿ“ ้œ€่ฆ Host ๆ‰นๅ‡†            ๐Ÿ“‹ ็›ดๆŽฅๆšด้œฒ็ป™ๆจกๅž‹         โ”‚
โ”‚  ๐ŸŒฐ ็‚’่œใ€ไธ‹ๅ•ใ€ๅ‘้‚ฎไปถ         ๐ŸŒฐ ่œๅ•ใ€่œ่ฐฑใ€ๅบ“ๅญ˜ๆธ…ๅ•    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๐Ÿ“‹ Prompt๏ผˆๆ็คบๆจกๆฟ๏ผ‰โ€”โ€” ๅ›บๅฎšๅฅ—้ค

Prompt ๆ˜ฏๆœๅŠกๅ™จ้ข„ๅฎšไน‰็š„ๆ็คบ่ฏๆจกๆฟ๏ผŒๅฏไปฅๅธฆๅ‚ๆ•ฐใ€‚

@mcp.prompt()
def daily_recommendation(preference: str) -> str:
    """ๆฏๆ—ฅๆŽจ่ๆ็คบๆจกๆฟ"""
    return f"""
    ไฝ ๆ˜ฏไธ€ไฝ็ฑณๅ…ถๆž—ไธ‰ๆ˜ŸไธปๅŽจใ€‚ๆ นๆฎ้กพๅฎขๅๅฅฝ"{preference}"๏ผŒ
    ไปŽไปŠๆ—ฅ่œๅ•ไธญๆŽจ่3้“่œ๏ผŒๅนถ่ฏดๆ˜ŽๆŽจ่็†็”ฑใ€‚
    ่ฏท็”จๆธฉๆš–ไผ˜้›…็š„่ฏญๆฐ”ๅ›ž็ญ”๏ผŒๆฏ้“่œ้…ไธ€ๅฅ่ฏ—ๆ„็š„ๆ่ฟฐใ€‚
    """

็ฌฌๅ››็ซ ๏ผš้€šไฟกๆœบๅˆถ โ€”โ€” ๆœๅŠกๅ‘˜ๆ€Žไนˆๅ†™็‚น่œๅ•๏ผŸ

MCP ๅบ•ๅฑ‚ไฝฟ็”จย JSON-RPC 2.0๏ผŒ่ฟ™ๆ˜ฏไธ€็ง้žๅธธ็ฎ€ๆด็š„ๆถˆๆฏๆ ผๅผใ€‚

ๆถˆๆฏๆœ‰ไธ‰็ง็ฑปๅž‹

// 1๏ธโƒฃ ่ฏทๆฑ‚ โ€”โ€” ๆœๅŠกๅ‘˜ๅ‘ๅŽๅŽจไธ‹ๅ•
{
    "jsonrpc": "2.0",
    "id": 1,                          // ่ฏทๆฑ‚็ผ–ๅท๏ผŒ็”จไบŽๅŒน้…ๅ“ๅบ”
    "method": "tools/call",           // ่ฆ่ฐƒ็”จ็š„ๆ–นๆณ•
    "params": {                       // ๅ‚ๆ•ฐ
        "name": "stir_fry",
        "arguments": {
            "ingredient": "่ฅฟ็บขๆŸฟ้ธก่›‹",
            "duration": 5
        }
    }
}

// 2๏ธโƒฃ ๅ“ๅบ” โ€”โ€” ๅŽๅŽจๅ‘Š่ฏ‰ๆœๅŠกๅ‘˜็ป“ๆžœ
{
    "jsonrpc": "2.0",
    "id": 1,                          // ๅฏนๅบ”่ฏทๆฑ‚็š„็ผ–ๅท
    "result": {
        "content": [{
            "type": "text",
            "text": "็”จๅคง็ซ็ฟป็‚’่ฅฟ็บขๆŸฟ้ธก่›‹๏ผŒ5ๅˆ†้’ŸๅŽๅ‡บ้”…๏ผŒ้ฆ™ๆฐ”ๅ››ๆบข๏ผ"
        }]
    }
}

// 3๏ธโƒฃ ้€š็Ÿฅ โ€”โ€” ๅŽๅŽจไธปๅŠจๅนฟๆ’ญ๏ผˆไธ้œ€่ฆๅ“ๅบ”๏ผ‰
{
    "jsonrpc": "2.0",
    "method": "notifications/resources/updated",  // ่ต„ๆบๆ›ดๆ–ฐไบ†
    "params": {
        "uri": "menu://today"
    }
}

ไผ ่พ“ๆ–นๅผ๏ผˆๆœๅŠกๅ‘˜ๆ€Žไนˆไผ ๅ•ๅญ๏ผ‰

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                                                              โ”‚
โ”‚  ๐Ÿ“ก stdio๏ผˆๆ ‡ๅ‡†่พ“ๅ…ฅ่พ“ๅ‡บ๏ผ‰                                      โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    stdin/stdout    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”               โ”‚
โ”‚  โ”‚  Host    โ”‚โ—„โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ–บโ”‚  Server  โ”‚               โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   ๏ผˆๅŒไธ€ๅฐ็”ต่„‘๏ผ‰    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ”‚
โ”‚  ๅœบๆ™ฏ๏ผšClaude Desktop ่ฐƒ็”จๆœฌๅœฐ MCP Server                     โ”‚
โ”‚  ็‰น็‚น๏ผšๆœ€็ฎ€ๅ•ใ€ๆœ€ๅฟซใ€ๆœ€ๅธธ็”จ                                    โ”‚
โ”‚                                                              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚                                                              โ”‚
โ”‚  ๐ŸŒ Streamable HTTP๏ผˆๅฏๆตๅผHTTP๏ผ‰                             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    HTTP ่ฏทๆฑ‚/ๅ“ๅบ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”             โ”‚
โ”‚  โ”‚  Host    โ”‚โ—„โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ–บโ”‚  Server  โ”‚             โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   ๏ผˆๅฏไปฅ่ทจ็ฝ‘็ปœ๏ผ‰      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜             โ”‚
โ”‚  ๅœบๆ™ฏ๏ผš่ฟœ็จ‹ MCP Serverใ€ไบ‘ๆœๅŠก                               โ”‚
โ”‚  ็‰น็‚น๏ผšๆ”ฏๆŒ่ฟœ็จ‹ใ€ๆ”ฏๆŒๆตๅผใ€ๆ”ฏๆŒๆ— ็Šถๆ€                           โ”‚
โ”‚                                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

็ฌฌไบ”็ซ ๏ผšๅฎŒๆ•ดๆ—ถๅบๅ›พ โ€”โ€” ไปŽ็”จๆˆท่ฏด่ฏๅˆฐๅพ—ๅˆฐ็ป“ๆžœ

ไธ‹้ขๆ˜ฏไธ€ไธชๅฎŒๆ•ด็š„ MCP ่ฐƒ็”จๆ—ถๅบ๏ผŒ็”จๆˆท่ฏดย  โ€œๅธฎๆˆ‘ๆŸฅไธ€ไธ‹ๅŒ—ไบฌๅคฉๆฐ”๏ผŒ็„ถๅŽ็ป™ๆˆ‘ๅ‡บ่กŒๅปบ่ฎฎโ€ ๏ผš

diagram(1).jpg

็ฌฌๅ…ญ็ซ ๏ผšๅŠจๆ‰‹ๅ†™ไธ€ไธชๅฎŒๆ•ด็š„ MCP Server

ๆˆ‘ไปฌๆฅๅ†™ไธ€ไธชๅ’–ๅ•กๅบ— MCP Server๏ผŒๅŒ…ๅซๅ…จ้ƒจไธ‰ๅคง่ƒฝๅŠ›๏ผš

้กน็›ฎ็ป“ๆž„

coffee-mcp-server/
โ”œโ”€โ”€ pyproject.toml          # ้กน็›ฎ้…็ฝฎ
โ””โ”€โ”€ server.py               # ๆœๅŠก็ซฏไปฃ็ 

pyproject.toml

[project]
name = "coffee-mcp-server"
version = "0.1.0"
description = "ไธ€ไธชๅ’–ๅ•กๅบ— MCP Server ็คบไพ‹"
requires-python = ">=3.10"
dependencies = [
    "mcp[cli]>=1.0.0",
]

[project.scripts]
coffee-server = "server:main"

server.py๏ผˆๅฎŒๆ•ดไปฃ็ ๏ผ‰

"""
โ˜• ๅ’–ๅ•กๅบ— MCP Server
ๅŒ…ๅซ๏ผšTools๏ผˆๅทฅๅ…ท๏ผ‰ใ€Resources๏ผˆ่ต„ๆบ๏ผ‰ใ€Prompts๏ผˆๆ็คบๆจกๆฟ๏ผ‰
"""
from mcp.server.fastmcp import FastMCP
from datetime import datetime

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ๐Ÿ—๏ธ ๅˆ›ๅปบ Server ๅฎžไพ‹
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
mcp = FastMCP(
    name="coffee-shop",
    version="0.1.0",
    instructions="ไฝ ๆ˜ฏไธ€ๅฎถ็ฒพๅ“ๅ’–ๅ•กๅบ—็š„ๆ™บ่ƒฝๅŠฉๆ‰‹๏ผŒๅฏไปฅๅธฎ้กพๅฎข็‚นๅ•ใ€ๆŸฅ่œๅ•ใ€ๆŽจ่้ฅฎๅ“ใ€‚"
)

# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ๐Ÿ“ฆ ๆจกๆ‹Ÿๆ•ฐๆฎ๏ผˆๅฎž้™…้กน็›ฎไธญไผš่ฟžๆŽฅๆ•ฐๆฎๅบ“๏ผ‰
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
MENU = {
    "็พŽๅผๅ’–ๅ•ก": {"price": 18, "stock": 50, "category": "็ปๅ…ธ"},
    "ๆ‹ฟ้“":     {"price": 24, "stock": 30, "category": "็ปๅ…ธ"},
    "ๅกๅธƒๅฅ‡่ฏบ": {"price": 26, "stock": 25, "category": "็ปๅ…ธ"},
    "ๆ‘ฉๅก":     {"price": 28, "stock": 20, "category": "้ฃŽๅ‘ณ"},
    "็„ฆ็ณ–็Ž›ๅฅ‡ๆœต": {"price": 32, "stock": 15, "category": "้ฃŽๅ‘ณ"},
    "ๆŠน่Œถๆ‹ฟ้“": {"price": 28, "stock": 18, "category": "็‰น่ฐƒ"},
    "ๅ†ฐๅšๅ…‹":   {"price": 35, "stock": 10, "category": "็‰น่ฐƒ"},
}

ORDERS = []  # ๅญ˜ๅ‚จๆ‰€ๆœ‰่ฎขๅ•


# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ๐Ÿ”ง TOOLS โ€”โ€” ๅŽจๅธˆ็š„"ๅŠจๆ‰‹่ƒฝๅŠ›"
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

@mcp.tool()
def order_drink(drink_name: str, size: str = "ไธญๆฏ", quantity: int = 1) -> str:
    """
    ไธ‹ๅ•่ดญไนฐ้ฅฎๅ“
    
    Args:
        drink_name: ้ฅฎๅ“ๅ็งฐ๏ผŒๅฆ‚"ๆ‹ฟ้“"ใ€"็พŽๅผๅ’–ๅ•ก"
        size: ๆฏๅž‹๏ผŒๅฏ้€‰"ๅฐๆฏ"ใ€"ไธญๆฏ"ใ€"ๅคงๆฏ"
        quantity: ่ดญไนฐๆ•ฐ้‡
    
    Returns:
        ไธ‹ๅ•็ป“ๆžœ๏ผŒๅŒ…ๅซ่ฎขๅ•ๅทๅ’Œๆ€ปไปท
    """
    # 1. ๆฃ€ๆŸฅ้ฅฎๅ“ๆ˜ฏๅฆๅญ˜ๅœจ
    if drink_name not in MENU:
        available = "ใ€".join(MENU.keys())
        return f"โŒ ๆŠฑๆญ‰๏ผŒๆˆ‘ไปฌๆฒกๆœ‰{drink_name}ใ€‚\n๐Ÿ“‹ ๅฏ้€‰้ฅฎๅ“๏ผš{available}"
    
    # 2. ๆฃ€ๆŸฅๅบ“ๅญ˜
    item = MENU[drink_name]
    if item["stock"] < quantity:
        return f"โŒ {drink_name}ๅบ“ๅญ˜ไธ่ถณ๏ผŒๅ‰ฉไฝ™{item['stock']}ๆฏใ€‚"
    
    # 3. ่ฎก็ฎ—ไปทๆ ผ๏ผˆๅคงๆฏ+4ๅ…ƒ๏ผŒๅฐๆฏ-3ๅ…ƒ๏ผ‰
    size_extra = {"ๅฐๆฏ": -3, "ไธญๆฏ": 0, "ๅคงๆฏ": 4}
    unit_price = item["price"] + size_extra.get(size, 0)
    total = unit_price * quantity
    
    # 4. ๆ‰ฃๅ‡ๅบ“ๅญ˜
    item["stock"] -= quantity
    
    # 5. ๅˆ›ๅปบ่ฎขๅ•
    order = {
        "id": f"COF-{len(ORDERS) + 1:04d}",
        "drink": drink_name,
        "size": size,
        "quantity": quantity,
        "unit_price": unit_price,
        "total": total,
        "time": datetime.now().strftime("%H:%M:%S"),
    }
    ORDERS.append(order)
    
    # 6. ่ฟ”ๅ›ž็ป“ๆžœ
    return (
        f"โœ… ไธ‹ๅ•ๆˆๅŠŸ๏ผ\n"
        f"๐Ÿ“ฆ ่ฎขๅ•ๅท๏ผš{order['id']}\n"
        f"โ˜• {size}{drink_name} x {quantity}\n"
        f"๐Ÿ’ฐ ๅ•ไปท๏ผšยฅ{unit_price}  ๆ€ป่ฎก๏ผšยฅ{total}\n"
        f"โฐ ๆ—ถ้—ด๏ผš{order['time']}\n"
        f"๐Ÿ“ฆ {drink_name}ๅ‰ฉไฝ™ๅบ“ๅญ˜๏ผš{item['stock']}ๆฏ"
    )


@mcp.tool()
def check_stock(drink_name: str = "") -> str:
    """
    ๆŸฅ่ฏข้ฅฎๅ“ๅบ“ๅญ˜
    
    Args:
        drink_name: ๅฏ้€‰๏ผŒๆŒ‡ๅฎš้ฅฎๅ“ๅ็งฐใ€‚ไธบ็ฉบๅˆ™ๆŸฅ่ฏขๆ‰€ๆœ‰ใ€‚
    
    Returns:
        ๅบ“ๅญ˜ไฟกๆฏ
    """
    if drink_name:
        if drink_name not in MENU:
            return f"โŒ ๆฒกๆœ‰่ฟ™ๆฌพ้ฅฎๅ“๏ผš{drink_name}"
        item = MENU[drink_name]
        status = "๐ŸŸข ๅ……่ถณ" if item["stock"] > 20 else "๐ŸŸก ๅๅฐ‘" if item["stock"] > 5 else "๐Ÿ”ด ็ดงๅผ "
        return f"โ˜• {drink_name}๏ผšๅบ“ๅญ˜ {item['stock']}ๆฏ {status}"
    
    # ๆŸฅ่ฏขๆ‰€ๆœ‰
    lines = ["๐Ÿ“‹ ๅ…จ้ƒจ้ฅฎๅ“ๅบ“ๅญ˜๏ผš\n"]
    for name, info in MENU.items():
        status = "๐ŸŸข" if info["stock"] > 20 else "๐ŸŸก" if info["stock"] > 5 else "๐Ÿ”ด"
        lines.append(f"  {status} {name}๏ผš{info['stock']}ๆฏ (ยฅ{info['price']})")
    return "\n".join(lines)


@mcp.tool()
def get_daily_sales() -> str:
    """
    ่Žทๅ–ไปŠๆ—ฅ้”€ๅ”ฎ็ปŸ่ฎก
    """
    if not ORDERS:
        return "๐Ÿ“Š ไปŠๆ—ฅๆš‚ๆ— ่ฎขๅ•ๆ•ฐๆฎใ€‚"
    
    total_orders = len(ORDERS)
    total_revenue = sum(o["total"] for o in ORDERS)
    total_cups = sum(o["quantity"] for o in ORDERS)
    
    # ๆœ€็•…้”€
    from collections import Counter
    best_seller = Counter(o["drink"] for o in ORDERS).most_common(1)[0]
    
    return (
        f"๐Ÿ“Š ไปŠๆ—ฅ้”€ๅ”ฎ็ปŸ่ฎก\n"
        f"{'โ”€' * 25}\n"
        f"๐Ÿงพ ่ฎขๅ•ๆ•ฐ๏ผš{total_orders} ๅ•\n"
        f"โ˜• ๆ€ปๆฏๆ•ฐ๏ผš{total_cups} ๆฏ\n"
        f"๐Ÿ’ฐ ๆ€ป่ฅๆ”ถ๏ผšยฅ{total_revenue}\n"
        f"๐Ÿ† ็•…้”€ๆฌพ๏ผš{best_seller[0]} ({best_seller[1]}ๆฏ)\n"
        f"{'โ”€' * 25}"
    )


# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ๐Ÿ“ฆ RESOURCES โ€”โ€” ้ฃŸๆๅบ“๏ผˆๅช่ฏปๆ•ฐๆฎ๏ผ‰
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

@mcp.resource("coffee://menu")
def get_full_menu() -> str:
    """
    ๅฎŒๆ•ด่œๅ•๏ผˆ่ต„ๆบ๏ผ‰
    URI: coffee://menu
    """
    lines = ["โ˜• ็ฒพๅ“ๅ’–ๅ•กๅบ— ยท ๅฎŒๆ•ด่œๅ•\n" + "โ•" * 35]
    
    # ๆŒ‰ๅˆ†็ฑปๅˆ†็ป„
    categories = {}
    for name, info in MENU.items():
        cat = info["category"]
        if cat not in categories:
            categories[cat] = []
        categories[cat].append((name, info))
    
    for cat, items in categories.items():
        lines.append(f"\nใ€{cat}ใ€‘")
        for name, info in items:
            lines.append(f"  {name}  ยฅ{info['price']}  ๅบ“ๅญ˜:{info['stock']}ๆฏ")
    
    lines.append(f"\n{'โ•' * 35}")
    lines.append(f"ๅ…ฑ {len(MENU)} ๆฌพ้ฅฎๅ“")
    return "\n".join(lines)


@mcp.resource("coffee://drink/{drink_name}")
def get_drink_detail(drink_name: str) -> str:
    """
    ๅ•ไธช้ฅฎๅ“่ฏฆๆƒ…๏ผˆๅธฆๅ‚ๆ•ฐ็š„่ต„ๆบ๏ผ‰
    URI: coffee://drink/ๆ‹ฟ้“
    """
    if drink_name not in MENU:
        return f"ๆœชๆ‰พๅˆฐ้ฅฎๅ“๏ผš{drink_name}"
    
    info = MENU[drink_name]
    
    # ๆจกๆ‹Ÿ่ฏฆ็ป†ๆ่ฟฐ
    descriptions = {
        "็พŽๅผๅ’–ๅ•ก": "ๆต“็ผฉๅ’–ๅ•กๅŠ ็ƒญๆฐด๏ผŒๅฃๆ„Ÿ้†‡ๅŽš๏ผŒ่‹ฆๅ‘ณๆ˜Žๆ˜พ๏ผŒ้€‚ๅˆๅ–œๆฌข็บฏ็ฒนๅ’–ๅ•กๅ‘ณ็š„ไบบใ€‚",
        "ๆ‹ฟ้“": "ๆต“็ผฉๅ’–ๅ•กๅŠ ๅคง้‡่’ธๆฑฝ็‰›ๅฅถ๏ผŒๅฅถ้ฆ™ๆต“้ƒ๏ผŒๅฃๆ„ŸๆŸ”ๅ’Œ๏ผŒๅ…ฅ้—จ้ฆ–้€‰ใ€‚",
        "ๅกๅธƒๅฅ‡่ฏบ": "ๆต“็ผฉๅ’–ๅ•กๅŠ ็ญ‰้‡ๅฅถๆณกๅ’Œ็‰›ๅฅถ๏ผŒๅฑ‚ๆฌกๅˆ†ๆ˜Ž๏ผŒๅฃๆ„Ÿ็ปตๅฏ†ใ€‚",
        "ๆ‘ฉๅก": "ๆต“็ผฉๅ’–ๅ•กๅŠ ๅทงๅ…‹ๅŠ›้…ฑๅ’Œ็‰›ๅฅถ๏ผŒ็”œ็พŽๆต“้ƒ๏ผŒๅƒๆถฒไฝ“ๅทงๅ…‹ๅŠ›่›‹็ณ•ใ€‚",
        "็„ฆ็ณ–็Ž›ๅฅ‡ๆœต": "ๆต“็ผฉๅ’–ๅ•กๅŠ ้ฆ™่‰็ณ–ๆต†ๅ’Œ็„ฆ็ณ–้…ฑ๏ผŒ็”œ่œœๆตชๆผซ๏ผŒ้ขœๅ€ผๆ‹…ๅฝ“ใ€‚",
        "ๆŠน่Œถๆ‹ฟ้“": "ๆ—ฅๆœฌๆŠน่ŒถๅŠ ่’ธๆฑฝ็‰›ๅฅถ๏ผŒๆธ…ๆ–ฐๅ›ž็”˜๏ผŒไธๅ–ๅ’–ๅ•กไนŸ่ƒฝ้€‰ใ€‚",
        "ๅ†ฐๅšๅ…‹": "ๅ†ทๅ†ปๆ็บฏ็‰›ๅฅถๅŠ ๆต“็ผฉๅ’–ๅ•ก๏ผŒๅฅถๅ‘ณ่ถ…็บงๆต“้ƒ๏ผŒๅ’–ๅ•ก็•Œ็š„็ˆฑ้ฉฌไป•ใ€‚",
    }
    
    desc = descriptions.get(drink_name, "ไธ€ๆฌพ็ฒพ้€‰้ฅฎๅ“ใ€‚")
    
    return (
        f"โ˜• {drink_name}\n"
        f"{'โ”€' * 30}\n"
        f"๐Ÿ’ฐ ไปทๆ ผ๏ผšยฅ{info['price']}\n"
        f"๐Ÿ“‚ ๅˆ†็ฑป๏ผš{info['category']}\n"
        f"๐Ÿ“ฆ ๅบ“ๅญ˜๏ผš{info['stock']}ๆฏ\n"
        f"๐Ÿ“ ๆ่ฟฐ๏ผš{desc}\n"
        f"{'โ”€' * 30}\n"
        f"ๆฏๅž‹ๅŠ ไปท๏ผšๅฐๆฏ -3ๅ…ƒ / ๅคงๆฏ +4ๅ…ƒ"
    )


@mcp.resource("coffee://orders/today")
def get_today_orders() -> str:
    """
    ไปŠๆ—ฅ่ฎขๅ•่ฎฐๅฝ•
    URI: coffee://orders/today
    """
    if not ORDERS:
        return "ไปŠๆ—ฅๆš‚ๆ— ่ฎขๅ•ใ€‚"
    
    lines = [f"๐Ÿ“‹ ไปŠๆ—ฅ่ฎขๅ•่ฎฐๅฝ• ({len(ORDERS)}ๅ•)\n" + "โ•" * 50]
    for o in ORDERS:
        lines.append(
            f"  {o['id']}  {o['time']}  "
            f"{o['size']}{o['drink']} x{o['quantity']}  "
            f"ยฅ{o['total']}"
        )
    return "\n".join(lines)


# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ๐Ÿ“‹ PROMPTS โ€”โ€” ๅ›บๅฎšๅฅ—้ค๏ผˆๆ็คบๆจกๆฟ๏ผ‰
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

@mcp.prompt()
def recommend_drink(preference: str = "", budget: int = 0) -> str:
    """
    ้ฅฎๅ“ๆŽจ่ๆ็คบๆจกๆฟ
    
    Args:
        preference: ้กพๅฎขๅฃๅ‘ณๅๅฅฝ๏ผŒๅฆ‚"ๅ–œๆฌข็”œ็š„"ใ€"ไธ่ฆๅคช่‹ฆ"
        budget: ้ข„็ฎ—ไธŠ้™๏ผŒ0่กจ็คบไธ้™
    """
    prompt = "ไฝ ๆ˜ฏไธ€ไฝไธ“ไธš็š„ๅ’–ๅ•กๅธˆ๏ผŒ่ฏทๆ นๆฎ้กพๅฎข้œ€ๆฑ‚ๆŽจ่้ฅฎๅ“ใ€‚\n\n"
    prompt += "้กพๅฎข้œ€ๆฑ‚๏ผš\n"
    if preference:
        prompt += f"- ๅฃๅ‘ณๅๅฅฝ๏ผš{preference}\n"
    if budget > 0:
        prompt += f"- ้ข„็ฎ—ไธŠ้™๏ผšยฅ{budget}\n"
    if not preference and budget == 0:
        prompt += "- ๆฒกๆœ‰็‰นๆฎŠ่ฆๆฑ‚๏ผŒ่ฏทๆŽจ่ๆœ€ๅ—ๆฌข่ฟŽ็š„\n"
    
    prompt += "\n่ฏทๅ…ˆๆŸฅ็œ‹ๅฎŒๆ•ด่œๅ•(coffee://menu)๏ผŒ็„ถๅŽๆŽจ่2-3ๆฌพๅˆ้€‚็š„้ฅฎๅ“๏ผŒ"
    prompt += "่ฏดๆ˜ŽๆŽจ่็†็”ฑ๏ผŒ็”จๆธฉๆš–ไบฒๅˆ‡็š„่ฏญๆฐ”ใ€‚"
    
    return prompt


@mcp.prompt()
def barista_guide(drink_name: str) -> str:
    """
    ๅ’–ๅ•กๅˆถไฝœๆŒ‡ๅ—ๆ็คบๆจกๆฟ
    
    Args:
        drink_name: ้ฅฎๅ“ๅ็งฐ
    """
    return f"""
    ่ฏทไปฅไธ“ไธšๅ’–ๅ•กๅธˆ็š„่บซไปฝ๏ผŒ่ฏฆ็ป†ไป‹็ปๅฆ‚ไฝ•ๅˆถไฝœไธ€ๆฏๅฎŒ็พŽ็š„{drink_name}ใ€‚
    
    ่ฆๆฑ‚๏ผš
    1. ๅ…ˆๆŸฅ็œ‹่ฏฅ้ฅฎๅ“็š„่ฏฆๆƒ…(coffee://drink/{drink_name})
    2. ๅˆ—ๅ‡บๆ‰€้œ€ๆๆ–™ๅ’Œๅทฅๅ…ท
    3. ๅˆ†ๆญฅ้ชค่ฎฒ่งฃๅˆถไฝœ่ฟ‡็จ‹
    4. ็ป™ๅ‡บไธ“ไธšๅฐๆŠ€ๅทง
    5. ็”จไผ˜้›…ไฝ†ๆ˜“ๆ‡‚็š„่ฏญ่จ€
    """


# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# ๐Ÿš€ ๅฏๅŠจ Server
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
def main():
    mcp.run(transport="stdio")

if __name__ == "__main__":
    main()

็ฌฌไธƒ็ซ ๏ผš่ฎฉ Claude Desktop ่ฟžๆŽฅไฝ ็š„ Server

ๅœจ Claude Desktop ็š„้…็ฝฎๆ–‡ไปถไธญๆทปๅŠ ๏ผš

macOS:ย ~/Library/Application Support/Claude/claude_desktop_config.json
Windows:ย %APPDATA%\Claude\claude_desktop_config.json

{
    "mcpServers": {
        "coffee-shop": {
            "command": "python",
            "args": ["/path/to/coffee-mcp-server/server.py"],
            "env": {}
        }
    }
}

ๅฆ‚ๆžœๆ˜ฏ npm ๅŒ…๏ผˆๆฏ”ๅฆ‚็คพๅŒบๅทฒๆœ‰็š„ Server๏ผ‰๏ผš

{
    "mcpServers": {
        "filesystem": {
            "command": "npx",
            "args": [
                "-y",
                "@modelcontextprotocol/server-filesystem",
                "/Users/you/documents"
            ]
        },
        "github": {
            "command": "npx",
            "args": ["-y", "@modelcontextprotocol/server-github"],
            "env": {
                "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxxx"
            }
        },
        "postgres": {
            "command": "npx",
            "args": [
                "-y",
                "@modelcontextprotocol/server-postgres",
                "postgresql://localhost:5432/mydb"
            ]
        }
    }
}

็ฌฌๅ…ซ็ซ ๏ผšๆœ€ไฝณๅฎž่ทต๏ผˆ่ต„ๆทฑๆžถๆž„ๅธˆ็š„็ป้ชŒไน‹่ฐˆ๏ผ‰

โœ… DO โ€”โ€” ๅบ”่ฏฅๅš็š„

# โ•โ•โ• 1. ๅทฅๅ…ทๆ่ฟฐ่ฆๅƒ็ป™ไบบ็œ‹็š„ไธ€ๆ ทๅ†™ๆธ…ๆฅš โ•โ•โ•
# โŒ ๅ็คบ่Œƒ
@mcp.tool()
def calc(a: int, b: int) -> int:
    """่ฎก็ฎ—"""
    return a + b

# โœ… ๅฅฝ็คบ่Œƒ
@mcp.tool()
def calculate_order_total(
    subtotal: float,
    discount_code: str = "",
    tax_rate: float = 0.06
) -> float:
    """
    ่ฎก็ฎ—่ฎขๅ•ๆœ€็ปˆๆ€ปไปท๏ผˆๅซ็จŽๅ’ŒๆŠ˜ๆ‰ฃ๏ผ‰
    
    Args:
        subtotal: ๅ•†ๅ“ๅฐ่ฎก้‡‘้ข๏ผˆ็จŽๅ‰๏ผŒๅ•ไฝ๏ผšๅ…ƒ๏ผ‰
        discount_code: ๆŠ˜ๆ‰ฃ็ ๏ผŒๅฏ้€‰ใ€‚็ฉบๅญ—็ฌฆไธฒ่กจ็คบๆ— ๆŠ˜ๆ‰ฃใ€‚
                      ๆ”ฏๆŒ็š„ๆŠ˜ๆ‰ฃ็ ๏ผšSAVE10(9ๆŠ˜)ใ€SAVE20(8ๆŠ˜)ใ€NEWUSER(7ๆŠ˜)
        tax_rate: ็จŽ็އ๏ผŒ้ป˜่ฎค6%๏ผˆไธญๅ›ฝ้ค้ฅฎๅขžๅ€ผ็จŽ๏ผ‰
    
    Returns:
        ๆœ€็ปˆๅบ”ไป˜้‡‘้ข๏ผˆๅ››่ˆไบ”ๅ…ฅๅˆฐๅˆ†๏ผ‰
    
    Examples:
        calculate_order_total(100, "SAVE10") โ†’ 95.4
        calculate_order_total(100) โ†’ 106.0
    """
    discount_map = {"SAVE10": 0.9, "SAVE20": 0.8, "NEWUSER": 0.7}
    rate = discount_map.get(discount_code, 1.0)
    return round(subtotal * rate * (1 + tax_rate), 2)


# โ•โ•โ• 2. ็”จ JSON Schema ็บฆๆŸๅ‚ๆ•ฐ โ•โ•โ•
from pydantic import BaseModel, Field

class OrderRequest(BaseModel):
    drink_name: str = Field(
        ..., 
        description="้ฅฎๅ“ๅ็งฐ",
        pattern=r"^[\u4e00-\u9fa5a-zA-Z]+$"  # ๅชๅ…่ฎธไธญ่‹ฑๆ–‡
    )
    size: str = Field(
        default="ไธญๆฏ",
        description="ๆฏๅž‹",
        json_schema_extra={"enum": ["ๅฐๆฏ", "ไธญๆฏ", "ๅคงๆฏ"]}
    )
    quantity: int = Field(
        default=1,
        ge=1,           # ๆœ€ๅฐๅ€ผ 1
        le=20,          # ๆœ€ๅคงๅ€ผ 20
        description="่ดญไนฐๆ•ฐ้‡๏ผŒ1-20ๆฏ"
    )

@mcp.tool()
def place_order(req: OrderRequest) -> str:
    """ไธ‹ๅ•่ดญไนฐ้ฅฎๅ“"""
    # req ๅทฒ็ป็ป่ฟ‡ Pydantic ้ชŒ่ฏ๏ผŒ็ฑปๅž‹ๅฎ‰ๅ…จ
    ...


# โ•โ•โ• 3. ่ฟ”ๅ›ž็ป“ๆž„ๅŒ–ๅ†…ๅฎน โ•โ•โ•
@mcp.tool()
def search_drinks(keyword: str) -> list[dict]:
    """
    ๆœ็ดข้ฅฎๅ“๏ผˆ่ฟ”ๅ›ž็ป“ๆž„ๅŒ–ๆ•ฐๆฎ๏ผŒๆ–นไพฟๆจกๅž‹่งฃๆž๏ผ‰
    """
    results = []
    for name, info in MENU.items():
        if keyword in name:
            results.append({
                "name": name,
                "price": info["price"],
                "stock": info["stock"],
                "available": info["stock"] > 0
            })
    return results


# โ•โ•โ• 4. ้”™่ฏฏๅค„็†่ฆๅ‹ๅฅฝ โ•โ•โ•
@mcp.tool()
def cancel_order(order_id: str) -> str:
    """
    ๅ–ๆถˆ่ฎขๅ•
    """
    # ๆ‰พไธๅˆฐ่ฎขๅ•
    order = next((o for o in ORDERS if o["id"] == order_id), None)
    if not order:
        return f"โŒ ๆœชๆ‰พๅˆฐ่ฎขๅ• {order_id}ใ€‚่ฏทๆฃ€ๆŸฅ่ฎขๅ•ๅทๆ˜ฏๅฆๆญฃ็กฎใ€‚"
    
    # ่ถ…ๆ—ถไธๅฏๅ–ๆถˆ
    if datetime.now().minute - int(order["time"].split(":")[1]) > 5:
        return f"โŒ ่ฎขๅ• {order_id} ๅทฒ่ถ…่ฟ‡5ๅˆ†้’Ÿ๏ผŒๆ— ๆณ•ๅ–ๆถˆใ€‚่ฏท่”็ณป้—จๅบ—ใ€‚"
    
    # ๆญฃๅธธๅ–ๆถˆ
    MENU[order["drink"]]["stock"] += order["quantity"]
    ORDERS.remove(order)
    return f"โœ… ่ฎขๅ• {order_id} ๅทฒๅ–ๆถˆ๏ผŒ{order['quantity']}ๆฏ{order['drink']}ๅทฒ้€€ๅ›žๅบ“ๅญ˜ใ€‚"


# โ•โ•โ• 5. ่ต„ๆบ URI ่ฆๆœ‰่ฏญไน‰ โ•โ•โ•
# โœ… ๅฅฝ็š„ URI ่ฎพ่ฎก
@mcp.resource("coffee://menu")                    # ่œๅ•
@mcp.resource("coffee://drink/{name}")            # ๅ•ไธช้ฅฎๅ“
@mcp.resource("coffee://orders/{date}")           # ๆŸๅคฉ่ฎขๅ•
@mcp.resource("coffee://stats/sales/{period}")    # ้”€ๅ”ฎ็ปŸ่ฎก

# โŒ ๅ็š„ URI ่ฎพ่ฎก
@mcp.resource("data/1")          # ๆ— ่ฏญไน‰
@mcp.resource("api/get-all")     # ๅƒ REST ่€Œไธๅƒ่ต„ๆบ
@mcp.resource("test")            # ๆ— ๆ„ไน‰

โŒ DONโ€™T โ€”โ€” ๅƒไธ‡ๅˆซๅš็š„

# โ•โ•โ• 1. ไธ่ฆๅœจๅทฅๅ…ท้‡Œๅšๅคงๆจกๅž‹็š„ๅทฅไฝœ โ•โ•โ•
# โŒ ๅ็คบ่Œƒ๏ผšๅทฅๅ…ท่‡ชๅทฑๅšๆ€ป็ป“
@mcp.tool()
def get_weather_with_analysis(city: str) -> str:
    """่Žทๅ–ๅคฉๆฐ”ๅนถๅˆ†ๆž"""
    weather = fetch_weather(city)
    analysis = f"ๅคฉๆฐ”ๆ˜ฏ{weather}๏ผŒๅปบ่ฎฎ{'ๅธฆไผž' if '้›จ' in weather else 'ๅ‡บ่กŒ'}"
    return analysis  # ๆจกๅž‹ๅบ”่ฏฅ่‡ชๅทฑๅˆ†ๆž๏ผŒไฝ ๅ‰ฅๅคบไบ†ๅฎƒ็š„่ƒฝๅŠ›

# โœ… ๅฅฝ็คบ่Œƒ๏ผšๅช่ฟ”ๅ›žๅŽŸๅง‹ๆ•ฐๆฎ
@mcp.tool()
def get_weather(city: str) -> dict:
    """่Žทๅ–ๅŸŽๅธ‚ๅคฉๆฐ”ๅŽŸๅง‹ๆ•ฐๆฎ"""
    return fetch_weather(city)  # ่ฎฉๆจกๅž‹ๆฅๅˆ†ๆžๅ’Œๅปบ่ฎฎ


# โ•โ•โ• 2. ไธ่ฆ่ฎฉๅทฅๅ…ทๅšๅคชๅคšไบ‹ โ•โ•โ•
# โŒ ๅ็คบ่Œƒ๏ผšไธ€ไธชๅทฅๅ…ทๅนฒๆ‰€ๆœ‰ไบ‹
@mcp.tool()
def coffee_operation(
    action: str,  # "order" / "cancel" / "check" / "recommend"
    **kwargs
) -> str:
    """ๅ’–ๅ•กๆ“ไฝœ๏ผˆไธ‡่ƒฝๅทฅๅ…ท๏ผ‰"""
    if action == "order": ...
    elif action == "cancel": ...
    elif action == "check": ...
    # ๆจกๅž‹ๅพˆ้šพๅ‡†็กฎ้€‰ๆ‹ฉ action

# โœ… ๅฅฝ็คบ่Œƒ๏ผšๆฏไธชๆ“ไฝœไธ€ไธชๅทฅๅ…ท
@mcp.tool()
def order_drink(...): ...
@mcp.tool()
def cancel_order(...): ...
@mcp.tool()
def check_stock(...): ...


# โ•โ•โ• 3. ไธ่ฆๅฟฝ็•ฅๅฎ‰ๅ…จๆ€ง โ•โ•โ•
# โŒ ๅ็คบ่Œƒ๏ผš็›ดๆŽฅๆ‰ง่กŒไปปๆ„ SQL
@mcp.tool()
def query_database(sql: str) -> str:
    """ๆ‰ง่กŒSQLๆŸฅ่ฏข"""
    return db.execute(sql)  # ๅฑ้™ฉ๏ผๆจกๅž‹ๅฏ่ƒฝๅ‘้€ DROP TABLE

# โœ… ๅฅฝ็คบ่Œƒ๏ผš้™ๅˆถๆŸฅ่ฏข่Œƒๅ›ด
@mcp.tool()
def query_orders(
    date_from: str,
    date_to: str,
    status: str = ""
) -> str:
    """ๆŸฅ่ฏข่ฎขๅ•่ฎฐๅฝ•๏ผˆๅช่ฏป๏ผŒ้™ๅฎš่Œƒๅ›ด๏ผ‰"""
    # ไฝฟ็”จๅ‚ๆ•ฐๅŒ–ๆŸฅ่ฏข๏ผŒๅชๅ…่ฎธๆŸฅ่ฏข orders ่กจ
    return db.query_orders(date_from, date_to, status)


# โ•โ•โ• 4. ไธ่ฆ่ฟ”ๅ›žๆตท้‡ๆ•ฐๆฎ โ•โ•โ•
# โŒ ๅ็คบ่Œƒ
@mcp.tool()
def get_all_logs() -> str:
    """่Žทๅ–ๆ‰€ๆœ‰ๆ—ฅๅฟ—"""  # ๅฏ่ƒฝ่ฟ”ๅ›ž 100MB ๆ•ฐๆฎ๏ผŒๆจกๅž‹็›ดๆŽฅๅดฉๆบƒ
    return open("/var/log/everything.log").read()

# โœ… ๅฅฝ็คบ่Œƒ
@mcp.tool()
def search_logs(
    keyword: str,
    limit: int = Field(default=20, le=100),
    start_time: str = "",
) -> str:
    """ๆœ็ดขๆ—ฅๅฟ—๏ผˆๆœ€ๅคš่ฟ”ๅ›ž100ๆก๏ผ‰"""
    ...

็ฌฌไน็ซ ๏ผš้ซ˜็บงๆŠ€ๅทง โ€”โ€” ่ต„ๆบ่ฎข้˜…ไธŽ่ฟ›ๅบฆ้€š็Ÿฅ

# โ•โ•โ• ่ต„ๆบ่ฎข้˜…๏ผˆๅŽๅŽจ้ฃŸๆๅ˜ไบ†๏ผŒไธปๅŠจ้€š็Ÿฅ๏ผ‰ โ•โ•โ•

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("smart-kitchen")

# ๅฎšไน‰ไธ€ไธชๅฏๆ›ดๆ–ฐ็š„่ต„ๆบ
@mcp.resource("kitchen://stock/{ingredient}")
async def get_stock(ingredient: str) -> str:
    """่Žทๅ–้ฃŸๆๅบ“ๅญ˜"""
    stock = await db.get_stock(ingredient)
    return f"{ingredient}: ๅ‰ฉไฝ™ {stock} ไปฝ"


# ๅฝ“ๅบ“ๅญ˜ๅ˜ๅŒ–ๆ—ถ๏ผŒ้€š็Ÿฅๆ‰€ๆœ‰่ฎข้˜…่€…
async def on_stock_changed(ingredient: str, new_stock: int):
    """ๅบ“ๅญ˜ๅ˜ๅŒ–ๅ›ž่ฐƒ"""
    if new_stock < 10:
        # ้€š็Ÿฅ่ต„ๆบๆ›ดๆ–ฐไบ†
        await mcp.request_context.session.send_resource_updated(
            "kitchen://stock/" + ingredient
        )
        # ่ฟ˜ๅฏไปฅไธปๅŠจๅ‘ๆ—ฅๅฟ—้€š็Ÿฅ
        await mcp.request_context.session.send_log_message(
            level="warning",
            data=f"โš ๏ธ {ingredient} ๅบ“ๅญ˜ไธ่ถณ๏ผŒไป…ๅ‰ฉ {new_stock} ไปฝ๏ผ"
        )


# โ•โ•โ• ่ฟ›ๅบฆ้€š็Ÿฅ๏ผˆ้•ฟๆ—ถ้—ดๆ“ไฝœ๏ผŒๆŠฅๅ‘Š่ฟ›ๅบฆ๏ผ‰ โ•โ•โ•
import asyncio

@mcp.tool()
async def batch_brew(drinks: list[str]) -> str:
    """
    ๆ‰น้‡ๅˆถไฝœ้ฅฎๅ“๏ผˆ่€—ๆ—ถๆ“ไฝœ๏ผŒไผšๆŠฅๅ‘Š่ฟ›ๅบฆ๏ผ‰
    """
    total = len(drinks)
    for i, drink in enumerate(drinks):
        # ๆจกๆ‹Ÿๅˆถไฝœ่ฟ‡็จ‹
        await asyncio.sleep(1)
        
        # ๅ‘้€่ฟ›ๅบฆ้€š็Ÿฅ
        await mcp.request_context.session.send_progress(
            progress_token="batch-brew-001",
            progress=i + 1,
            total=total,
            message=f"ๆญฃๅœจๅˆถไฝœ {drink} ({i+1}/{total})"
        )
    
    return f"โœ… {total}ๆฏ้ฅฎๅ“ๅ…จ้ƒจๅˆถไฝœๅฎŒๆˆ๏ผ"

็ฌฌๅ็ซ ๏ผš่ฐƒ่ฏ•ๆŠ€ๅทง โ€”โ€” MCP Inspector

MCP ๅฎ˜ๆ–นๆไพ›ไบ†ไธ€ไธช่ถ…ๅฅฝ็”จ็š„่ฐƒ่ฏ•ๅทฅๅ…ทย MCP Inspector๏ผš

# ็›ดๆŽฅๅฏๅŠจ๏ผŒไผšๆ‰“ๅผ€ไธ€ไธช Web ็•Œ้ข
npx @modelcontextprotocol/inspector python server.py

# ๆˆ–่€…่ฐƒ่ฏ•่ฟœ็จ‹ Server
npx @modelcontextprotocol/inspector --transport streamable-http http://localhost:8080/mcp

Inspector ็•Œ้ขๅฏไปฅ๏ผš

  • ๐Ÿ“‹ ๆŸฅ็œ‹ๆ‰€ๆœ‰ Tools / Resources / Prompts
  • ๐Ÿงช ๆ‰‹ๅŠจ่ฐƒ็”จไปปๆ„ๅทฅๅ…ท๏ผˆๅกซๅ‚ๆ•ฐ โ†’ ็œ‹็ป“ๆžœ๏ผ‰
  • ๐Ÿ“ก ๅฎžๆ—ถๆŸฅ็œ‹ๆ‰€ๆœ‰ JSON-RPC ๆถˆๆฏ๏ผˆๅƒๆŠ“ๅŒ…ไธ€ๆ ท๏ผ‰
  • ๐Ÿ” ่ฐƒ่ฏ•่ฟžๆŽฅ้—ฎ้ข˜

็ฌฌๅไธ€็ซ ๏ผšๅธธ่ง้—ฎ้ข˜ๆŽ’ๆŸฅ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  ้—ฎ้ข˜็Žฐ่ฑก                    โ”‚  ๅฏ่ƒฝๅŽŸๅ›         โ”‚  ่งฃๅ†ณๆ–นๆกˆ    โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  Claude ็œ‹ไธๅˆฐๅทฅๅ…ท           โ”‚  ServerๆฒกๅฏๅŠจ    โ”‚  ๆฃ€ๆŸฅ้…็ฝฎJSON โ”‚
โ”‚                              โ”‚  ๅˆๅง‹ๅŒ–ๅคฑ่ดฅ      โ”‚  ็œ‹stderrๆ—ฅๅฟ—โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  ๆจกๅž‹ไธ่ฐƒ็”จๅทฅๅ…ท               โ”‚  ๆ่ฟฐไธๆธ…ๆฅš      โ”‚  ไผ˜ๅŒ–docstringโ”‚
โ”‚                              โ”‚  ๅ‚ๆ•ฐๅๆจก็ณŠ      โ”‚  ๅŠ enum็บฆๆŸ  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  ๅทฅๅ…ท่ฐƒ็”จๆŠฅ้”™                 โ”‚  ๅ‚ๆ•ฐ็ฑปๅž‹้”™่ฏฏ    โ”‚  ๅŠ Pydantic  โ”‚
โ”‚                              โ”‚  ็ผบๅฐ‘ๅฟ…ๅกซๅ‚ๆ•ฐ    โ”‚  ่ฎพ้ป˜่ฎคๅ€ผ    โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  ่ฟžๆŽฅ่ถ…ๆ—ถ                    โ”‚  stdio้˜ปๅกž      โ”‚  ไธ่ฆ็”จinput()โ”‚
โ”‚                              โ”‚  ๅฏๅŠจๅคชๆ…ข       โ”‚  ๆ‡’ๅŠ ่ฝฝ่ต„ๆบ  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  ่ฟ”ๅ›žๆ•ฐๆฎ่ขซๆˆชๆ–ญ               โ”‚  ่ถ…่ฟ‡token้™ๅˆถ   โ”‚  ๅˆ†้กต/ๆ‘˜่ฆ   โ”‚
โ”‚                              โ”‚  ๆ ผๅผ้”™่ฏฏ       โ”‚  ่ฟ”ๅ›ž็บฏๆ–‡ๆœฌ  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

็ปˆ็ซ ๏ผšไธ€ๅผ ๅ›พๆ€ป็ป“ MCP ๅ…จ่ฒŒ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                      MCP ๅ่ฎฎๅ…จๆ™ฏๅ›พ                              โ”‚
โ”‚                                                                 โ”‚
โ”‚  ็”จๆˆท โ”€โ”€โ–ถ Host โ”€โ”€โ–ถ AIๆจกๅž‹ โ”€โ”€โ”                                   โ”‚
โ”‚                           โ”‚                                    โ”‚
โ”‚                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”                               โ”‚
โ”‚                    โ”‚ ้œ€่ฆๅค–้ƒจ่ƒฝๅŠ›๏ผŸโ”‚                               โ”‚
โ”‚                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜                               โ”‚
โ”‚                    Yes     โ”‚     No                              โ”‚
โ”‚                   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                            โ”‚
โ”‚                   โ–ผ                 โ–ผ                            โ”‚
โ”‚            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   ็›ดๆŽฅๅ›ž็ญ”็”จๆˆท                       โ”‚
โ”‚            โ”‚ ้€‰ๆ‹ฉๅทฅๅ…ท/่ต„ๆบ โ”‚                                     โ”‚
โ”‚            โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                     โ”‚
โ”‚                   โ”‚                                             โ”‚
โ”‚         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                   โ”‚
โ”‚         โ–ผ         โ–ผ         โ–ผ                                   โ”‚
โ”‚      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”                                โ”‚
โ”‚      โ”‚Tool  โ”‚ โ”‚Resrc โ”‚ โ”‚Promptโ”‚  โ† ไธ‰ๅคง่ƒฝๅŠ›                     โ”‚
โ”‚      โ”‚ๅŠจๆ‰‹ๅšโ”‚ โ”‚่ฏปๆ•ฐๆฎโ”‚ โ”‚ๆจกๆฟๅŒ–โ”‚                                โ”‚
โ”‚      โ””โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜                                โ”‚
โ”‚         โ”‚        โ”‚        โ”‚                                     โ”‚
โ”‚         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                     โ”‚
โ”‚                  โ–ผ                                              โ”‚
โ”‚           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                       โ”‚
โ”‚           โ”‚  Client     โ”‚  โ† JSON-RPC 2.0                      โ”‚
โ”‚           โ”‚  (ๅ่ฎฎ็ฟป่ฏ‘)  โ”‚                                       โ”‚
โ”‚           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                       โ”‚
โ”‚                  โ”‚                                              โ”‚
โ”‚         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                      โ”‚
โ”‚         โ–ผ        โ–ผ        โ–ผ                                      โ”‚
โ”‚      stdio    HTTP    (ๆœชๆฅๆ›ดๅคš)   โ† ไผ ่พ“ๅฑ‚                      โ”‚
โ”‚         โ”‚        โ”‚                                              โ”‚
โ”‚         โ–ผ        โ–ผ                                              โ”‚
โ”‚      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                                        โ”‚
โ”‚      โ”‚    Server       โ”‚  โ† ไฝ ็š„ไปฃ็ ่ฟ่กŒๅœจ่ฟ™้‡Œ                   โ”‚
โ”‚      โ”‚  (่ƒฝๅŠ›ๆไพ›่€…)    โ”‚                                        โ”‚
โ”‚      โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                        โ”‚
โ”‚                                                                 โ”‚
โ”‚  โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•    โ”‚
โ”‚  ๆ ธๅฟƒไปทๅ€ผ๏ผšไธ€ๆฌก็ผ–ๅ†™๏ผŒๅˆฐๅค„ไฝฟ็”จ๏ผˆไปปไฝ• MCP Host ้ƒฝ่ƒฝ่ฐƒ็”จไฝ ็š„Server๏ผ‰ โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

ๆœ€ๅŽ็š„ไธ€ๅฅ่ฏๆ€ป็ป“

MCP ๅฐฑๆ˜ฏ AI ไธ–็•Œ้‡Œ็š„ USB ๆŽฅๅฃๆ ‡ๅ‡†ใ€‚

ไปฅๅ‰ๆฏไธช AI ๅบ”็”จ่ฆ่ฟžๆŽฅๅค–้ƒจๅทฅๅ…ท๏ผŒ้ƒฝๅพ—่‡ชๅทฑๅ†™ไธ€ๅฅ—"้ฉฑๅŠจ็จ‹ๅบ"ใ€‚MCP ๅ‡บ็ŽฐๅŽ๏ผŒๅทฅๅ…ทๅผ€ๅ‘่€…ๅช่ฆๆŒ‰ๆ ‡ๅ‡†ๅ†™ไธ€ไธช Server๏ผŒๆ‰€ๆœ‰ๆ”ฏๆŒ MCP ็š„ AI ๅบ”็”จ้ƒฝ่ƒฝ็›ดๆŽฅ็”จ โ€”โ€”ย ๅฐฑๅƒ U ็›˜ๆ’ไธŠไปปไฝ•็”ต่„‘้ƒฝ่ƒฝ็”จไธ€ๆ ท็ฎ€ๅ•ใ€‚

ๅธŒๆœ›่ฟ™ไธชๆ•…ไบ‹ๅ’Œไปฃ็ ่ƒฝ่ฎฉไฝ ๅฝปๅบ•็†่งฃ MCP๏ผๅฆ‚ๆžœไฝ ๆƒณๆŠŠๅ’–ๅ•กๅบ— Serverย ่ท‘่ตทๆฅ๏ผŒๆˆ–่€…ๆƒณไบ†่งฃๆ›ด้ซ˜็บง็š„็”จๆณ•๏ผˆๆฏ”ๅฆ‚ๅคš Server ๅไฝœใ€่ฟœ็จ‹้ƒจ็ฝฒ๏ผ‰๏ผŒ้šๆ—ถ้—ฎๆˆ‘ โ˜•