3534 lines
224 KiB
HTML
3534 lines
224 KiB
HTML
<!DOCTYPE html><html lang="en" class="no-js"><head>
|
|
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
|
|
<meta name="description" content="MCP Server">
|
|
|
|
|
|
|
|
<link rel="canonical" href="https://modelcontextprotocol.github.io/python-sdk/server/">
|
|
|
|
|
|
<link rel="prev" href="../installation/">
|
|
|
|
|
|
<link rel="next" href="../client/">
|
|
|
|
|
|
<link rel="icon" href="../assets/images/favicon.png">
|
|
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.19">
|
|
|
|
|
|
|
|
<title>Building Servers - MCP Server</title>
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../assets/stylesheets/main.7e37652d.min.css">
|
|
|
|
|
|
<link rel="stylesheet" href="../assets/stylesheets/palette.06af60db.min.css">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
|
|
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
|
|
|
|
|
|
|
|
<link rel="stylesheet" href="../assets/_mkdocstrings.css">
|
|
|
|
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<meta property="og:type" content="website">
|
|
|
|
<meta property="og:title" content="Building Servers - MCP Server">
|
|
|
|
<meta property="og:description" content="MCP Server">
|
|
|
|
<meta property="og:image" content="https://modelcontextprotocol.github.io/python-sdk/assets/images/social/server.png">
|
|
|
|
<meta property="og:image:type" content="image/png">
|
|
|
|
<meta property="og:image:width" content="1200">
|
|
|
|
<meta property="og:image:height" content="630">
|
|
|
|
<meta property="og:url" content="https://modelcontextprotocol.github.io/python-sdk/server/">
|
|
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
|
|
<meta name="twitter:title" content="Building Servers - MCP Server">
|
|
|
|
<meta name="twitter:description" content="MCP Server">
|
|
|
|
<meta name="twitter:image" content="https://modelcontextprotocol.github.io/python-sdk/assets/images/social/server.png">
|
|
|
|
|
|
|
|
<link href="../assets/stylesheets/glightbox.min.css" rel="stylesheet"><script src="../assets/javascripts/glightbox.min.js"></script><style id="glightbox-style">
|
|
html.glightbox-open { overflow: initial; height: 100%; }
|
|
.gslide-title { margin-top: 0px; user-select: text; }
|
|
.gslide-desc { color: #666; user-select: text; }
|
|
.gslide-image img { background: white; }
|
|
.gscrollbar-fixer { padding-right: 15px; }
|
|
.gdesc-inner { font-size: 0.75rem; }
|
|
body[data-md-color-scheme="slate"] .gdesc-inner { background: var(--md-default-bg-color); }
|
|
body[data-md-color-scheme="slate"] .gslide-title { color: var(--md-default-fg-color); }
|
|
body[data-md-color-scheme="slate"] .gslide-desc { color: var(--md-default-fg-color); }
|
|
</style></head>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="black">
|
|
|
|
|
|
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
|
|
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
|
|
<label class="md-overlay" for="__drawer"></label>
|
|
<div data-md-component="skip">
|
|
|
|
|
|
<a href="#building-mcp-servers" class="md-skip">
|
|
Skip to content
|
|
</a>
|
|
|
|
</div>
|
|
<div data-md-component="announce">
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<header class="md-header md-header--shadow" data-md-component="header">
|
|
<nav class="md-header__inner md-grid" aria-label="Header">
|
|
<a href=".." title="MCP Server" class="md-header__button md-logo" aria-label="MCP Server" data-md-component="logo">
|
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"></path></svg>
|
|
|
|
</a>
|
|
<label class="md-header__button md-icon" for="__drawer">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"></path></svg>
|
|
</label>
|
|
<div class="md-header__title" data-md-component="header-title">
|
|
<div class="md-header__ellipsis">
|
|
<div class="md-header__topic">
|
|
<span class="md-ellipsis">
|
|
MCP Server
|
|
</span>
|
|
</div>
|
|
<div class="md-header__topic" data-md-component="header-topic">
|
|
<span class="md-ellipsis">
|
|
|
|
Building Servers
|
|
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<form class="md-header__option" data-md-component="palette">
|
|
|
|
|
|
|
|
|
|
<input class="md-option" data-md-color-media="(prefers-color-scheme)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="black" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_0">
|
|
|
|
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2a7 7 0 0 0-7 7c0 2.38 1.19 4.47 3 5.74V17a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-2.26c1.81-1.27 3-3.36 3-5.74a7 7 0 0 0-7-7M9 21a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-1H9z"></path></svg>
|
|
</label>
|
|
|
|
|
|
|
|
|
|
|
|
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="black" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
|
|
|
|
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_2" hidden>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2a7 7 0 0 1 7 7c0 2.38-1.19 4.47-3 5.74V17a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1v-2.26C6.19 13.47 5 11.38 5 9a7 7 0 0 1 7-7M9 21v-1h6v1a1 1 0 0 1-1 1h-4a1 1 0 0 1-1-1m3-17a5 5 0 0 0-5 5c0 2.05 1.23 3.81 3 4.58V16h4v-2.42c1.77-.77 3-2.53 3-4.58a5 5 0 0 0-5-5"></path></svg>
|
|
</label>
|
|
|
|
|
|
|
|
|
|
|
|
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="white" data-md-color-accent="white" aria-label="Switch to system preference" type="radio" name="__palette" id="__palette_2">
|
|
|
|
<label class="md-header__button md-icon" title="Switch to system preference" for="__palette_0" hidden>
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9 2c3.87 0 7 3.13 7 7 0 2.38-1.19 4.47-3 5.74V17c0 .55-.45 1-1 1H6c-.55 0-1-.45-1-1v-2.26C3.19 13.47 2 11.38 2 9c0-3.87 3.13-7 7-7M6 21v-1h6v1c0 .55-.45 1-1 1H7c-.55 0-1-.45-1-1M9 4C6.24 4 4 6.24 4 9c0 2.05 1.23 3.81 3 4.58V16h4v-2.42c1.77-.77 3-2.53 3-4.58 0-2.76-2.24-5-5-5m10 9h-2l-3.2 9h1.9l.7-2h3.2l.7 2h1.9zm-2.15 5.65L18 15l1.15 3.65z"></path></svg>
|
|
</label>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
|
|
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-header__button md-icon" for="__search">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"></path></svg>
|
|
</label>
|
|
<div class="md-search" data-md-component="search" role="dialog">
|
|
<label class="md-search__overlay" for="__search"></label>
|
|
<div class="md-search__inner" role="search">
|
|
<form class="md-search__form" name="search">
|
|
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
|
|
<label class="md-search__icon md-icon" for="__search">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"></path></svg>
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"></path></svg>
|
|
</label>
|
|
<nav class="md-search__options" aria-label="Search">
|
|
|
|
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path></svg>
|
|
</button>
|
|
</nav>
|
|
|
|
<div class="md-search__suggest" data-md-component="search-suggest"></div>
|
|
|
|
</form>
|
|
<div class="md-search__output">
|
|
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
|
|
<div class="md-search-result" data-md-component="search-result">
|
|
<div class="md-search-result__meta">
|
|
Initializing search
|
|
</div>
|
|
<ol class="md-search-result__list" role="presentation"></ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-header__source">
|
|
<a href="https://github.com/modelcontextprotocol/python-sdk" title="Go to repository" class="md-source" data-md-component="source">
|
|
<div class="md-source__icon md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path fill="currentColor" d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"></path></svg>
|
|
</div>
|
|
<div class="md-source__repository">
|
|
modelcontextprotocol/python-sdk
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
</nav>
|
|
|
|
</header>
|
|
|
|
<div class="md-container" data-md-component="container">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<main class="md-main" data-md-component="main">
|
|
<div class="md-main__inner md-grid">
|
|
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation">
|
|
<div class="md-sidebar__scrollwrap">
|
|
<div class="md-sidebar__inner">
|
|
|
|
|
|
|
|
|
|
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
|
|
<label class="md-nav__title" for="__drawer">
|
|
<a href=".." title="MCP Server" class="md-nav__button md-logo" aria-label="MCP Server" data-md-component="logo">
|
|
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"></path></svg>
|
|
|
|
</a>
|
|
MCP Server
|
|
</label>
|
|
|
|
<div class="md-nav__source">
|
|
<a href="https://github.com/modelcontextprotocol/python-sdk" title="Go to repository" class="md-source" data-md-component="source">
|
|
<div class="md-source__icon md-icon">
|
|
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path fill="currentColor" d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"></path></svg>
|
|
</div>
|
|
<div class="md-source__repository">
|
|
modelcontextprotocol/python-sdk
|
|
</div>
|
|
</a>
|
|
</div>
|
|
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href=".." class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Introduction
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../installation/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Installation
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
|
|
|
|
|
|
|
|
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" checked>
|
|
|
|
|
|
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Documentation
|
|
|
|
</span>
|
|
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="true">
|
|
<label class="md-nav__title" for="__nav_3">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
Documentation
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--active">
|
|
|
|
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__link md-nav__link--active" for="__toc">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Building Servers
|
|
|
|
</span>
|
|
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
<a href="./" class="md-nav__link md-nav__link--active">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Building Servers
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
|
|
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__title" for="__toc">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
Table of contents
|
|
</label>
|
|
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#core-concepts" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Core Concepts
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Core Concepts">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#server" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Server
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#resources" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Resources
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Resources">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#resource-templates-and-template-reading" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Resource Templates and Template Reading
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#binary-resources" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Binary Resources
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#resource-subscriptions" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Resource Subscriptions
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#tools" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Tools
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Tools">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#error-handling" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Error Handling
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#structured-output" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Structured Output
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Structured Output">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#advanced-direct-calltoolresult" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Advanced: Direct CallToolResult
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#prompts" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Prompts
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Prompts">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#prompts-with-embedded-resources" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Prompts with Embedded Resources
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#prompts-with-image-content" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Prompts with Image Content
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#prompt-change-notifications" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Prompt Change Notifications
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#icons" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Icons
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#images" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Images
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#audio" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Audio
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#embedded-resource-results" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Embedded Resource Results
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#tool-change-notifications" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Tool Change Notifications
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#context" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Context
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Context">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#getting-context-in-functions" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Getting Context in Functions
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#context-properties-and-methods" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Context Properties and Methods
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#completions" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Completions
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#elicitation" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Elicitation
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Elicitation">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#elicitation-with-enum-values" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Elicitation with Enum Values
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#elicitation-complete-notification" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Elicitation Complete Notification
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#sampling" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Sampling
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#logging-and-notifications" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Logging and Notifications
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Logging and Notifications">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#setting-the-logging-level" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Setting the Logging Level
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#authentication" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Authentication
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#fastmcp-properties" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
FastMCP Properties
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#session-properties-and-methods" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Session Properties and Methods
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#request-context-properties" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Request Context Properties
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#running-your-server" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Running Your Server
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Running Your Server">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#development-mode" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Development Mode
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#claude-desktop-integration" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Claude Desktop Integration
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#direct-execution" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Direct Execution
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#streamable-http-transport" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Streamable HTTP Transport
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Streamable HTTP Transport">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#cors-configuration-for-browser-based-clients" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
CORS Configuration for Browser-Based Clients
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#mounting-to-an-existing-asgi-server" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Mounting to an Existing ASGI Server
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Mounting to an Existing ASGI Server">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#streamablehttp-servers" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
StreamableHTTP servers
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="StreamableHTTP servers">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#basic-mounting" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Basic mounting
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#host-based-routing" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Host-based routing
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#multiple-servers-with-path-configuration" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Multiple servers with path configuration
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#path-configuration-at-initialization" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Path configuration at initialization
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#sse-servers" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
SSE servers
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#advanced-usage" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Advanced Usage
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../client/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Writing Clients
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../protocol/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Protocol Features
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../low-level-server/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Low-Level Server
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../authorization/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Authorization
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../testing/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Testing
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--section md-nav__item--nested">
|
|
|
|
|
|
|
|
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4">
|
|
|
|
|
|
<div class="md-nav__link md-nav__container">
|
|
<a href="../experimental/" class="md-nav__link ">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Experimental
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
|
|
|
|
<label class="md-nav__link " for="__nav_4" id="__nav_4_label" tabindex="">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
</div>
|
|
|
|
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
|
|
<label class="md-nav__title" for="__nav_4">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
Experimental
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item md-nav__item--nested">
|
|
|
|
|
|
|
|
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4_2">
|
|
|
|
|
|
<label class="md-nav__link" for="__nav_4_2" id="__nav_4_2_label" tabindex="0">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Tasks
|
|
|
|
</span>
|
|
|
|
|
|
<span class="md-nav__icon md-icon"></span>
|
|
</label>
|
|
|
|
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_4_2_label" aria-expanded="false">
|
|
<label class="md-nav__title" for="__nav_4_2">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
Tasks
|
|
</label>
|
|
<ul class="md-nav__list" data-md-scrollfix>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../experimental/tasks/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Introduction
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../experimental/tasks-server/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Server Implementation
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../experimental/tasks-client/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
Client Usage
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<li class="md-nav__item">
|
|
<a href="../api/" class="md-nav__link">
|
|
|
|
|
|
|
|
<span class="md-ellipsis">
|
|
API Reference
|
|
|
|
</span>
|
|
|
|
|
|
</a>
|
|
</li>
|
|
|
|
|
|
|
|
</ul>
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc">
|
|
<div class="md-sidebar__scrollwrap">
|
|
<div class="md-sidebar__inner">
|
|
|
|
|
|
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<label class="md-nav__title" for="__toc">
|
|
<span class="md-nav__icon md-icon"></span>
|
|
Table of contents
|
|
</label>
|
|
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#core-concepts" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Core Concepts
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Core Concepts">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#server" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Server
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#resources" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Resources
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Resources">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#resource-templates-and-template-reading" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Resource Templates and Template Reading
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#binary-resources" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Binary Resources
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#resource-subscriptions" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Resource Subscriptions
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#tools" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Tools
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Tools">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#error-handling" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Error Handling
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#structured-output" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Structured Output
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Structured Output">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#advanced-direct-calltoolresult" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Advanced: Direct CallToolResult
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#prompts" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Prompts
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Prompts">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#prompts-with-embedded-resources" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Prompts with Embedded Resources
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#prompts-with-image-content" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Prompts with Image Content
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#prompt-change-notifications" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Prompt Change Notifications
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#icons" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Icons
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#images" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Images
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#audio" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Audio
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#embedded-resource-results" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Embedded Resource Results
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#tool-change-notifications" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Tool Change Notifications
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#context" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Context
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Context">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#getting-context-in-functions" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Getting Context in Functions
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#context-properties-and-methods" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Context Properties and Methods
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#completions" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Completions
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#elicitation" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Elicitation
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Elicitation">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#elicitation-with-enum-values" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Elicitation with Enum Values
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#elicitation-complete-notification" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Elicitation Complete Notification
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#sampling" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Sampling
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#logging-and-notifications" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Logging and Notifications
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Logging and Notifications">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#setting-the-logging-level" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Setting the Logging Level
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#authentication" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Authentication
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#fastmcp-properties" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
FastMCP Properties
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#session-properties-and-methods" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Session Properties and Methods
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#request-context-properties" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Request Context Properties
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#running-your-server" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Running Your Server
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Running Your Server">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#development-mode" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Development Mode
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#claude-desktop-integration" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Claude Desktop Integration
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#direct-execution" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Direct Execution
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#streamable-http-transport" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Streamable HTTP Transport
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Streamable HTTP Transport">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#cors-configuration-for-browser-based-clients" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
CORS Configuration for Browser-Based Clients
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#mounting-to-an-existing-asgi-server" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Mounting to an Existing ASGI Server
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="Mounting to an Existing ASGI Server">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#streamablehttp-servers" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
StreamableHTTP servers
|
|
</span>
|
|
</a>
|
|
|
|
<nav class="md-nav" aria-label="StreamableHTTP servers">
|
|
<ul class="md-nav__list">
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#basic-mounting" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Basic mounting
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#host-based-routing" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Host-based routing
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#multiple-servers-with-path-configuration" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Multiple servers with path configuration
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#path-configuration-at-initialization" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Path configuration at initialization
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#sse-servers" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
SSE servers
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
</nav>
|
|
|
|
</li>
|
|
|
|
<li class="md-nav__item">
|
|
<a href="#advanced-usage" class="md-nav__link">
|
|
<span class="md-ellipsis">
|
|
Advanced Usage
|
|
</span>
|
|
</a>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="md-content" data-md-component="content">
|
|
<article class="md-content__inner md-typeset">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<h1 id="building-mcp-servers">Building MCP Servers</h1>
|
|
<h2 id="core-concepts">Core Concepts</h2>
|
|
<h3 id="server">Server</h3>
|
|
<p>The FastMCP server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:</p>
|
|
<!-- snippet-source examples/snippets/servers/lifespan_example.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""Example showing lifespan support for startup/shutdown with strong typing."""</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">collections.abc</span><span class="w"> </span><span class="kn">import</span> <span class="n">AsyncIterator</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">contextlib</span><span class="w"> </span><span class="kn">import</span> <span class="n">asynccontextmanager</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">dataclasses</span><span class="w"> </span><span class="kn">import</span> <span class="n">dataclass</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.session</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServerSession</span>
|
|
|
|
|
|
<span class="c1"># Mock database class for example</span>
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">Database</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Mock database class for example."""</span>
|
|
|
|
<span class="nd">@classmethod</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">connect</span><span class="p">(</span><span class="bp">cls</span><span class="p">)</span> <span class="o">-></span> <span class="s2">"Database"</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Connect to database."""</span>
|
|
<span class="k">return</span> <span class="bp">cls</span><span class="p">()</span>
|
|
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">disconnect</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Disconnect from database."""</span>
|
|
<span class="k">pass</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">query</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Execute a query."""</span>
|
|
<span class="k">return</span> <span class="s2">"Query result"</span>
|
|
|
|
|
|
<span class="nd">@dataclass</span>
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">AppContext</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Application context with typed dependencies."""</span>
|
|
|
|
<span class="n">db</span><span class="p">:</span> <span class="n">Database</span>
|
|
|
|
|
|
<span class="nd">@asynccontextmanager</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">app_lifespan</span><span class="p">(</span><span class="n">server</span><span class="p">:</span> <span class="n">FastMCP</span><span class="p">)</span> <span class="o">-></span> <span class="n">AsyncIterator</span><span class="p">[</span><span class="n">AppContext</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""Manage application lifecycle with type-safe context."""</span>
|
|
<span class="c1"># Initialize on startup</span>
|
|
<span class="n">db</span> <span class="o">=</span> <span class="k">await</span> <span class="n">Database</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span>
|
|
<span class="k">try</span><span class="p">:</span>
|
|
<span class="k">yield</span> <span class="n">AppContext</span><span class="p">(</span><span class="n">db</span><span class="o">=</span><span class="n">db</span><span class="p">)</span>
|
|
<span class="k">finally</span><span class="p">:</span>
|
|
<span class="c1"># Cleanup on shutdown</span>
|
|
<span class="k">await</span> <span class="n">db</span><span class="o">.</span><span class="n">disconnect</span><span class="p">()</span>
|
|
|
|
|
|
<span class="c1"># Pass lifespan to server</span>
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"My App"</span><span class="p">,</span> <span class="n">lifespan</span><span class="o">=</span><span class="n">app_lifespan</span><span class="p">)</span>
|
|
|
|
|
|
<span class="c1"># Access type-safe lifespan context in tools</span>
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">query_db</span><span class="p">(</span><span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="n">AppContext</span><span class="p">])</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Tool that uses initialized resources."""</span>
|
|
<span class="n">db</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">.</span><span class="n">request_context</span><span class="o">.</span><span class="n">lifespan_context</span><span class="o">.</span><span class="n">db</span>
|
|
<span class="k">return</span> <span class="n">db</span><span class="o">.</span><span class="n">query</span><span class="p">()</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/lifespan_example.py">examples/snippets/servers/lifespan_example.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h3 id="resources">Resources</h3>
|
|
<p>Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects:</p>
|
|
<!-- snippet-source examples/snippets/servers/basic_resource.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"Resource Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">"file://documents/</span><span class="si">{name}</span><span class="s2">"</span><span class="p">)</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">read_document</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Read a document by name."""</span>
|
|
<span class="c1"># This would normally read from disk</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Content of </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">"</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">"config://settings"</span><span class="p">)</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_settings</span><span class="p">()</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Get application settings."""</span>
|
|
<span class="k">return</span> <span class="s2">"""{</span>
|
|
<span class="s2"> "theme": "dark",</span>
|
|
<span class="s2"> "language": "en",</span>
|
|
<span class="s2"> "debug": false</span>
|
|
<span class="s2">}"""</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/basic_resource.py">examples/snippets/servers/basic_resource.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h4 id="resource-templates-and-template-reading">Resource Templates and Template Reading</h4>
|
|
<p>Resources with URI parameters (e.g., <code>{name}</code>) are registered as templates. When a client reads a templated resource, the URI parameters are extracted and passed to the function:</p>
|
|
<!-- snippet-source examples/snippets/servers/resource_templates.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Template Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">"users://</span><span class="si">{user_id}</span><span class="s2">/profile"</span><span class="p">)</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_user_profile</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Read a specific user's profile. The user_id is extracted from the URI."""</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s1">'</span><span class="se">{{</span><span class="s1">"user_id": "</span><span class="si">{</span><span class="n">user_id</span><span class="si">}</span><span class="s1">", "name": "User </span><span class="si">{</span><span class="n">user_id</span><span class="si">}</span><span class="s1">"</span><span class="se">}}</span><span class="s1">'</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/resource_templates.py">examples/snippets/servers/resource_templates.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<p>Clients read a template resource by providing a concrete URI:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="c1"># Client-side: read a template resource with a concrete URI</span>
|
|
<span class="n">content</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">read_resource</span><span class="p">(</span><span class="s2">"users://alice/profile"</span><span class="p">)</span>
|
|
</code></pre></div>
|
|
<p>Templates with multiple parameters work the same way:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="nd">@mcp</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">"repos://</span><span class="si">{owner}</span><span class="s2">/</span><span class="si">{repo}</span><span class="s2">/readme"</span><span class="p">)</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_readme</span><span class="p">(</span><span class="n">owner</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">repo</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Each URI parameter becomes a function argument."""</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"README for </span><span class="si">{</span><span class="n">owner</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">repo</span><span class="si">}</span><span class="s2">"</span>
|
|
</code></pre></div>
|
|
<h4 id="binary-resources">Binary Resources</h4>
|
|
<p>Resources can return binary data by returning <code>bytes</code> instead of <code>str</code>. Set the <code>mime_type</code> to indicate the content type:</p>
|
|
<!-- snippet-source examples/snippets/servers/binary_resources.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Binary Resource Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">"images://logo.png"</span><span class="p">,</span> <span class="n">mime_type</span><span class="o">=</span><span class="s2">"image/png"</span><span class="p">)</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_logo</span><span class="p">()</span> <span class="o">-></span> <span class="nb">bytes</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Return a binary image resource."""</span>
|
|
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"logo.png"</span><span class="p">,</span> <span class="s2">"rb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/binary_resources.py">examples/snippets/servers/binary_resources.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<p>Binary content is automatically base64-encoded and returned as <code>BlobResourceContents</code> in the MCP response.</p>
|
|
<h4 id="resource-subscriptions">Resource Subscriptions</h4>
|
|
<p>Clients can subscribe to resource updates. Use the low-level server API to handle subscription and unsubscription requests:</p>
|
|
<!-- snippet-source examples/snippets/servers/resource_subscriptions.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.lowlevel</span><span class="w"> </span><span class="kn">import</span> <span class="n">Server</span>
|
|
|
|
<span class="n">server</span> <span class="o">=</span> <span class="n">Server</span><span class="p">(</span><span class="s2">"Subscription Example"</span><span class="p">)</span>
|
|
|
|
<span class="n">subscriptions</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">set</span><span class="p">[</span><span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># uri -> set of session ids</span>
|
|
|
|
|
|
<span class="nd">@server</span><span class="o">.</span><span class="n">subscribe_resource</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">handle_subscribe</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Handle a client subscribing to a resource."""</span>
|
|
<span class="n">subscriptions</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">uri</span><span class="p">),</span> <span class="nb">set</span><span class="p">())</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">"current_session"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@server</span><span class="o">.</span><span class="n">unsubscribe_resource</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">handle_unsubscribe</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Handle a client unsubscribing from a resource."""</span>
|
|
<span class="k">if</span> <span class="nb">str</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span> <span class="ow">in</span> <span class="n">subscriptions</span><span class="p">:</span>
|
|
<span class="n">subscriptions</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">uri</span><span class="p">)]</span><span class="o">.</span><span class="n">discard</span><span class="p">(</span><span class="s2">"current_session"</span><span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/resource_subscriptions.py">examples/snippets/servers/resource_subscriptions.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<p>When a subscribed resource changes, notify clients with <code>send_resource_updated()</code>:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">pydantic</span><span class="w"> </span><span class="kn">import</span> <span class="n">AnyUrl</span>
|
|
|
|
<span class="c1"># After modifying resource data:</span>
|
|
<span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">send_resource_updated</span><span class="p">(</span><span class="n">AnyUrl</span><span class="p">(</span><span class="s2">"resource://my-resource"</span><span class="p">))</span>
|
|
</code></pre></div>
|
|
<h3 id="tools">Tools</h3>
|
|
<p>Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:</p>
|
|
<!-- snippet-source examples/snippets/servers/basic_tool.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"Tool Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Add two numbers together."""</span>
|
|
<span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">unit</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">"celsius"</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Get weather for a city."""</span>
|
|
<span class="c1"># This would normally call a weather API</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Weather in </span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="s2">: 22degrees</span><span class="si">{</span><span class="n">unit</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span><span class="si">}</span><span class="s2">"</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/basic_tool.py">examples/snippets/servers/basic_tool.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h4 id="error-handling">Error Handling</h4>
|
|
<p>When a tool encounters an error, it should signal this to the client rather than returning a normal result. The MCP protocol uses the <code>isError</code> flag on <code>CallToolResult</code> to distinguish error responses from successful ones. There are three ways to handle errors:</p>
|
|
<!-- snippet-source examples/snippets/servers/tool_errors.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""Example showing how to handle and return errors from tools."""</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp.exceptions</span><span class="w"> </span><span class="kn">import</span> <span class="n">ToolError</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.types</span><span class="w"> </span><span class="kn">import</span> <span class="n">CallToolResult</span><span class="p">,</span> <span class="n">TextContent</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Tool Error Handling Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="c1"># Option 1: Raise ToolError for expected error conditions.</span>
|
|
<span class="c1"># The error message is returned to the client with isError=True.</span>
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">divide</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Divide two numbers."""</span>
|
|
<span class="k">if</span> <span class="n">b</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
|
|
<span class="k">raise</span> <span class="n">ToolError</span><span class="p">(</span><span class="s2">"Cannot divide by zero"</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">a</span> <span class="o">/</span> <span class="n">b</span>
|
|
|
|
|
|
<span class="c1"># Option 2: Unhandled exceptions are automatically caught and</span>
|
|
<span class="c1"># converted to error responses with isError=True.</span>
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">read_config</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Read a configuration file."""</span>
|
|
<span class="c1"># If this raises FileNotFoundError, the client receives an</span>
|
|
<span class="c1"># error response like "Error executing tool read_config: ..."</span>
|
|
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
|
|
|
|
|
<span class="c1"># Option 3: Return CallToolResult directly for full control</span>
|
|
<span class="c1"># over error responses, including custom content.</span>
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">validate_input</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">CallToolResult</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Validate input data."""</span>
|
|
<span class="n">errors</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
|
|
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o"><</span> <span class="mi">3</span><span class="p">:</span>
|
|
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">"Input must be at least 3 characters"</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">data</span><span class="o">.</span><span class="n">isascii</span><span class="p">():</span>
|
|
<span class="n">errors</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">"Input must be ASCII only"</span><span class="p">)</span>
|
|
|
|
<span class="k">if</span> <span class="n">errors</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="n">CallToolResult</span><span class="p">(</span>
|
|
<span class="n">content</span><span class="o">=</span><span class="p">[</span><span class="n">TextContent</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">"text"</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">errors</span><span class="p">))],</span>
|
|
<span class="n">isError</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">CallToolResult</span><span class="p">(</span>
|
|
<span class="n">content</span><span class="o">=</span><span class="p">[</span><span class="n">TextContent</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">"text"</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">"Validation passed"</span><span class="p">)],</span>
|
|
<span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/tool_errors.py">examples/snippets/servers/tool_errors.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<ul>
|
|
<li><strong><code>ToolError</code></strong> is the preferred approach for most cases — raise it with a descriptive message and the framework handles the rest.</li>
|
|
<li><strong>Unhandled exceptions</strong> are caught automatically, so tools won't crash the server. The exception message is forwarded to the client as an error response.</li>
|
|
<li><strong><code>CallToolResult</code></strong> with <code>isError=True</code> gives full control when you need to customize the error content or include multiple content items.</li>
|
|
</ul>
|
|
<p>Tools can optionally receive a Context object by including a parameter with the <code>Context</code> type annotation. This context is automatically injected by the FastMCP framework and provides access to MCP capabilities:</p>
|
|
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.session</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServerSession</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"Progress Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">long_running_task</span><span class="p">(</span><span class="n">task_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="kc">None</span><span class="p">],</span> <span class="n">steps</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">5</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Execute a task with progress updates."""</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Starting: </span><span class="si">{</span><span class="n">task_name</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
|
|
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">steps</span><span class="p">):</span>
|
|
<span class="n">progress</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="n">steps</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">report_progress</span><span class="p">(</span>
|
|
<span class="n">progress</span><span class="o">=</span><span class="n">progress</span><span class="p">,</span>
|
|
<span class="n">total</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span>
|
|
<span class="n">message</span><span class="o">=</span><span class="sa">f</span><span class="s2">"Step </span><span class="si">{</span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">steps</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Completed step </span><span class="si">{</span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Task '</span><span class="si">{</span><span class="n">task_name</span><span class="si">}</span><span class="s2">' completed"</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/tool_progress.py">examples/snippets/servers/tool_progress.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h4 id="structured-output">Structured Output</h4>
|
|
<p>Tools will return structured results by default, if their return type
|
|
annotation is compatible. Otherwise, they will return unstructured results.</p>
|
|
<p>Structured output supports these return types:</p>
|
|
<ul>
|
|
<li>Pydantic models (BaseModel subclasses)</li>
|
|
<li>TypedDicts</li>
|
|
<li>Dataclasses and other classes with type hints</li>
|
|
<li><code>dict[str, T]</code> (where T is any JSON-serializable type)</li>
|
|
<li>Primitive types (str, int, float, bool, bytes, None) - wrapped in <code>{"result": value}</code></li>
|
|
<li>Generic types (list, tuple, Union, Optional, etc.) - wrapped in <code>{"result": value}</code></li>
|
|
</ul>
|
|
<p>Classes without type hints cannot be serialized for structured output. Only
|
|
classes with properly annotated attributes will be converted to Pydantic models
|
|
for schema generation and validation.</p>
|
|
<p>Structured results are automatically validated against the output schema
|
|
generated from the annotation. This ensures the tool returns well-typed,
|
|
validated data that clients can easily process.</p>
|
|
<p><strong>Note:</strong> For backward compatibility, unstructured results are also
|
|
returned. Unstructured results are provided for backward compatibility
|
|
with previous versions of the MCP specification, and are quirks-compatible
|
|
with previous versions of FastMCP in the current version of the SDK.</p>
|
|
<p><strong>Note:</strong> In cases where a tool function's return type annotation
|
|
causes the tool to be classified as structured <em>and this is undesirable</em>,
|
|
the classification can be suppressed by passing <code>structured_output=False</code>
|
|
to the <code>@tool</code> decorator.</p>
|
|
<h5 id="advanced-direct-calltoolresult">Advanced: Direct CallToolResult</h5>
|
|
<p>For full control over tool responses including the <code>_meta</code> field (for passing data to client applications without exposing it to the model), you can return <code>CallToolResult</code> directly:</p>
|
|
<!-- snippet-source examples/snippets/servers/direct_call_tool_result.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""Example showing direct CallToolResult return for advanced control."""</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Annotated</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">pydantic</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseModel</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.types</span><span class="w"> </span><span class="kn">import</span> <span class="n">CallToolResult</span><span class="p">,</span> <span class="n">TextContent</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"CallToolResult Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">ValidationModel</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
|
|
<span class="w"> </span><span class="sd">"""Model for validating structured output."""</span>
|
|
|
|
<span class="n">status</span><span class="p">:</span> <span class="nb">str</span>
|
|
<span class="n">data</span><span class="p">:</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">advanced_tool</span><span class="p">()</span> <span class="o">-></span> <span class="n">CallToolResult</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Return CallToolResult directly for full control including _meta field."""</span>
|
|
<span class="k">return</span> <span class="n">CallToolResult</span><span class="p">(</span>
|
|
<span class="n">content</span><span class="o">=</span><span class="p">[</span><span class="n">TextContent</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">"text"</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">"Response visible to the model"</span><span class="p">)],</span>
|
|
<span class="n">_meta</span><span class="o">=</span><span class="p">{</span><span class="s2">"hidden"</span><span class="p">:</span> <span class="s2">"data for client applications only"</span><span class="p">},</span>
|
|
<span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">validated_tool</span><span class="p">()</span> <span class="o">-></span> <span class="n">Annotated</span><span class="p">[</span><span class="n">CallToolResult</span><span class="p">,</span> <span class="n">ValidationModel</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""Return CallToolResult with structured output validation."""</span>
|
|
<span class="k">return</span> <span class="n">CallToolResult</span><span class="p">(</span>
|
|
<span class="n">content</span><span class="o">=</span><span class="p">[</span><span class="n">TextContent</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">"text"</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">"Validated response"</span><span class="p">)],</span>
|
|
<span class="n">structuredContent</span><span class="o">=</span><span class="p">{</span><span class="s2">"status"</span><span class="p">:</span> <span class="s2">"success"</span><span class="p">,</span> <span class="s2">"data"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"result"</span><span class="p">:</span> <span class="mi">42</span><span class="p">}},</span>
|
|
<span class="n">_meta</span><span class="o">=</span><span class="p">{</span><span class="s2">"internal"</span><span class="p">:</span> <span class="s2">"metadata"</span><span class="p">},</span>
|
|
<span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">empty_result_tool</span><span class="p">()</span> <span class="o">-></span> <span class="n">CallToolResult</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""For empty results, return CallToolResult with empty content."""</span>
|
|
<span class="k">return</span> <span class="n">CallToolResult</span><span class="p">(</span><span class="n">content</span><span class="o">=</span><span class="p">[])</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/direct_call_tool_result.py">examples/snippets/servers/direct_call_tool_result.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<p><strong>Important:</strong> <code>CallToolResult</code> must always be returned (no <code>Optional</code> or <code>Union</code>). For empty results, use <code>CallToolResult(content=[])</code>. For optional simple types, use <code>str | None</code> without <code>CallToolResult</code>.</p>
|
|
<!-- snippet-source examples/snippets/servers/structured_output.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""Example showing structured output with tools."""</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">TypedDict</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">pydantic</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">Field</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Structured Output Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="c1"># Using Pydantic models for rich structured data</span>
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">WeatherData</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
|
|
<span class="w"> </span><span class="sd">"""Weather information structure."""</span>
|
|
|
|
<span class="n">temperature</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Temperature in Celsius"</span><span class="p">)</span>
|
|
<span class="n">humidity</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Humidity percentage"</span><span class="p">)</span>
|
|
<span class="n">condition</span><span class="p">:</span> <span class="nb">str</span>
|
|
<span class="n">wind_speed</span><span class="p">:</span> <span class="nb">float</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_weather</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">WeatherData</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Get weather for a city - returns structured data."""</span>
|
|
<span class="c1"># Simulated weather data</span>
|
|
<span class="k">return</span> <span class="n">WeatherData</span><span class="p">(</span>
|
|
<span class="n">temperature</span><span class="o">=</span><span class="mf">22.5</span><span class="p">,</span>
|
|
<span class="n">humidity</span><span class="o">=</span><span class="mf">45.0</span><span class="p">,</span>
|
|
<span class="n">condition</span><span class="o">=</span><span class="s2">"sunny"</span><span class="p">,</span>
|
|
<span class="n">wind_speed</span><span class="o">=</span><span class="mf">5.2</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
|
|
|
|
<span class="c1"># Using TypedDict for simpler structures</span>
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">LocationInfo</span><span class="p">(</span><span class="n">TypedDict</span><span class="p">):</span>
|
|
<span class="n">latitude</span><span class="p">:</span> <span class="nb">float</span>
|
|
<span class="n">longitude</span><span class="p">:</span> <span class="nb">float</span>
|
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_location</span><span class="p">(</span><span class="n">address</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">LocationInfo</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Get location coordinates"""</span>
|
|
<span class="k">return</span> <span class="n">LocationInfo</span><span class="p">(</span><span class="n">latitude</span><span class="o">=</span><span class="mf">51.5074</span><span class="p">,</span> <span class="n">longitude</span><span class="o">=-</span><span class="mf">0.1278</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="s2">"London, UK"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="c1"># Using dict[str, Any] for flexible schemas</span>
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_statistics</span><span class="p">(</span><span class="n">data_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">float</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""Get various statistics"""</span>
|
|
<span class="k">return</span> <span class="p">{</span><span class="s2">"mean"</span><span class="p">:</span> <span class="mf">42.5</span><span class="p">,</span> <span class="s2">"median"</span><span class="p">:</span> <span class="mf">40.0</span><span class="p">,</span> <span class="s2">"std_dev"</span><span class="p">:</span> <span class="mf">5.2</span><span class="p">}</span>
|
|
|
|
|
|
<span class="c1"># Ordinary classes with type hints work for structured output</span>
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">UserProfile</span><span class="p">:</span>
|
|
<span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
|
|
<span class="n">age</span><span class="p">:</span> <span class="nb">int</span>
|
|
<span class="n">email</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">age</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">email</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">age</span> <span class="o">=</span> <span class="n">age</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">email</span> <span class="o">=</span> <span class="n">email</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_user</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">UserProfile</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Get user profile - returns structured data"""</span>
|
|
<span class="k">return</span> <span class="n">UserProfile</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"Alice"</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="s2">"alice@example.com"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="c1"># Classes WITHOUT type hints cannot be used for structured output</span>
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">UntypedConfig</span><span class="p">:</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">setting1</span><span class="p">,</span> <span class="n">setting2</span><span class="p">):</span> <span class="c1"># type: ignore[reportMissingParameterType]</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">setting1</span> <span class="o">=</span> <span class="n">setting1</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">setting2</span> <span class="o">=</span> <span class="n">setting2</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_config</span><span class="p">()</span> <span class="o">-></span> <span class="n">UntypedConfig</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""This returns unstructured output - no schema generated"""</span>
|
|
<span class="k">return</span> <span class="n">UntypedConfig</span><span class="p">(</span><span class="s2">"value1"</span><span class="p">,</span> <span class="s2">"value2"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="c1"># Lists and other types are wrapped automatically</span>
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">list_cities</span><span class="p">()</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""Get a list of cities"""</span>
|
|
<span class="k">return</span> <span class="p">[</span><span class="s2">"London"</span><span class="p">,</span> <span class="s2">"Paris"</span><span class="p">,</span> <span class="s2">"Tokyo"</span><span class="p">]</span>
|
|
<span class="c1"># Returns: {"result": ["London", "Paris", "Tokyo"]}</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_temperature</span><span class="p">(</span><span class="n">city</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Get temperature as a simple float"""</span>
|
|
<span class="k">return</span> <span class="mf">22.5</span>
|
|
<span class="c1"># Returns: {"result": 22.5}</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/structured_output.py">examples/snippets/servers/structured_output.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h3 id="prompts">Prompts</h3>
|
|
<p>Prompts are reusable templates that help LLMs interact with your server effectively:</p>
|
|
<!-- snippet-source examples/snippets/servers/basic_prompt.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp.prompts</span><span class="w"> </span><span class="kn">import</span> <span class="n">base</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"Prompt Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">prompt</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Code Review"</span><span class="p">)</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">review_code</span><span class="p">(</span><span class="n">code</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Please review this code:</span><span class="se">\n\n</span><span class="si">{</span><span class="n">code</span><span class="si">}</span><span class="s2">"</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">prompt</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"Debug Assistant"</span><span class="p">)</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">debug_error</span><span class="p">(</span><span class="n">error</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">base</span><span class="o">.</span><span class="n">Message</span><span class="p">]:</span>
|
|
<span class="k">return</span> <span class="p">[</span>
|
|
<span class="n">base</span><span class="o">.</span><span class="n">UserMessage</span><span class="p">(</span><span class="s2">"I'm seeing this error:"</span><span class="p">),</span>
|
|
<span class="n">base</span><span class="o">.</span><span class="n">UserMessage</span><span class="p">(</span><span class="n">error</span><span class="p">),</span>
|
|
<span class="n">base</span><span class="o">.</span><span class="n">AssistantMessage</span><span class="p">(</span><span class="s2">"I'll help debug that. What have you tried so far?"</span><span class="p">),</span>
|
|
<span class="p">]</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/basic_prompt.py">examples/snippets/servers/basic_prompt.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h4 id="prompts-with-embedded-resources">Prompts with Embedded Resources</h4>
|
|
<p>Prompts can include embedded resources to provide file contents or data alongside the conversation messages:</p>
|
|
<!-- snippet-source examples/snippets/servers/prompt_embedded_resources.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">mcp.types</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">types</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp.prompts</span><span class="w"> </span><span class="kn">import</span> <span class="n">base</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Embedded Resource Prompt Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">prompt</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">review_file</span><span class="p">(</span><span class="n">filename</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">base</span><span class="o">.</span><span class="n">Message</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""Review a file with its contents embedded."""</span>
|
|
<span class="n">file_content</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
|
<span class="k">return</span> <span class="p">[</span>
|
|
<span class="n">base</span><span class="o">.</span><span class="n">UserMessage</span><span class="p">(</span>
|
|
<span class="n">content</span><span class="o">=</span><span class="n">types</span><span class="o">.</span><span class="n">TextContent</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">"text"</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="sa">f</span><span class="s2">"Please review </span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s2">:"</span><span class="p">),</span>
|
|
<span class="p">),</span>
|
|
<span class="n">base</span><span class="o">.</span><span class="n">UserMessage</span><span class="p">(</span>
|
|
<span class="n">content</span><span class="o">=</span><span class="n">types</span><span class="o">.</span><span class="n">EmbeddedResource</span><span class="p">(</span>
|
|
<span class="nb">type</span><span class="o">=</span><span class="s2">"resource"</span><span class="p">,</span>
|
|
<span class="n">resource</span><span class="o">=</span><span class="n">types</span><span class="o">.</span><span class="n">TextResourceContents</span><span class="p">(</span>
|
|
<span class="n">uri</span><span class="o">=</span><span class="sa">f</span><span class="s2">"file://</span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="n">text</span><span class="o">=</span><span class="n">file_content</span><span class="p">,</span>
|
|
<span class="n">mimeType</span><span class="o">=</span><span class="s2">"text/plain"</span><span class="p">,</span>
|
|
<span class="p">),</span>
|
|
<span class="p">),</span>
|
|
<span class="p">),</span>
|
|
<span class="p">]</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/prompt_embedded_resources.py">examples/snippets/servers/prompt_embedded_resources.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h4 id="prompts-with-image-content">Prompts with Image Content</h4>
|
|
<p>Prompts can include images using <code>ImageContent</code> or the <code>Image</code> helper class:</p>
|
|
<!-- snippet-source examples/snippets/servers/prompt_image_content.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">mcp.types</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">types</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp.prompts</span><span class="w"> </span><span class="kn">import</span> <span class="n">base</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp.utilities.types</span><span class="w"> </span><span class="kn">import</span> <span class="n">Image</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Image Prompt Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">prompt</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">describe_image</span><span class="p">(</span><span class="n">image_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">list</span><span class="p">[</span><span class="n">base</span><span class="o">.</span><span class="n">Message</span><span class="p">]:</span>
|
|
<span class="w"> </span><span class="sd">"""Prompt that includes an image for analysis."""</span>
|
|
<span class="n">img</span> <span class="o">=</span> <span class="n">Image</span><span class="p">(</span><span class="n">path</span><span class="o">=</span><span class="n">image_path</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="p">[</span>
|
|
<span class="n">base</span><span class="o">.</span><span class="n">UserMessage</span><span class="p">(</span>
|
|
<span class="n">content</span><span class="o">=</span><span class="n">types</span><span class="o">.</span><span class="n">TextContent</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">"text"</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">"Describe this image:"</span><span class="p">),</span>
|
|
<span class="p">),</span>
|
|
<span class="n">base</span><span class="o">.</span><span class="n">UserMessage</span><span class="p">(</span>
|
|
<span class="n">content</span><span class="o">=</span><span class="n">img</span><span class="o">.</span><span class="n">to_image_content</span><span class="p">(),</span>
|
|
<span class="p">),</span>
|
|
<span class="p">]</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/prompt_image_content.py">examples/snippets/servers/prompt_image_content.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h4 id="prompt-change-notifications">Prompt Change Notifications</h4>
|
|
<p>When your server dynamically adds or removes prompts, notify connected clients:</p>
|
|
<!-- snippet-source examples/snippets/servers/prompt_change_notifications.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.session</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServerSession</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Dynamic Prompts"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">update_prompts</span><span class="p">(</span><span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="kc">None</span><span class="p">])</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Update available prompts and notify clients."""</span>
|
|
<span class="c1"># ... modify prompts ...</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">send_prompt_list_changed</span><span class="p">()</span>
|
|
<span class="k">return</span> <span class="s2">"Prompts updated"</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/prompt_change_notifications.py">examples/snippets/servers/prompt_change_notifications.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h3 id="icons">Icons</h3>
|
|
<p>MCP servers can provide icons for UI display. Icons can be added to the server implementation, tools, resources, and prompts:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span><span class="p">,</span> <span class="n">Icon</span>
|
|
|
|
<span class="c1"># Create an icon from a file path or URL</span>
|
|
<span class="n">icon</span> <span class="o">=</span> <span class="n">Icon</span><span class="p">(</span>
|
|
<span class="n">src</span><span class="o">=</span><span class="s2">"icon.png"</span><span class="p">,</span>
|
|
<span class="n">mimeType</span><span class="o">=</span><span class="s2">"image/png"</span><span class="p">,</span>
|
|
<span class="n">sizes</span><span class="o">=</span><span class="p">[</span><span class="s2">"64x64"</span><span class="p">]</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="c1"># Add icons to server</span>
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span>
|
|
<span class="s2">"My Server"</span><span class="p">,</span>
|
|
<span class="n">website_url</span><span class="o">=</span><span class="s2">"https://example.com"</span><span class="p">,</span>
|
|
<span class="n">icons</span><span class="o">=</span><span class="p">[</span><span class="n">icon</span><span class="p">]</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="c1"># Add icons to tools, resources, and prompts</span>
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">(</span><span class="n">icons</span><span class="o">=</span><span class="p">[</span><span class="n">icon</span><span class="p">])</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">my_tool</span><span class="p">():</span>
|
|
<span class="w"> </span><span class="sd">"""Tool with an icon."""</span>
|
|
<span class="k">return</span> <span class="s2">"result"</span>
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">resource</span><span class="p">(</span><span class="s2">"demo://resource"</span><span class="p">,</span> <span class="n">icons</span><span class="o">=</span><span class="p">[</span><span class="n">icon</span><span class="p">])</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">my_resource</span><span class="p">():</span>
|
|
<span class="w"> </span><span class="sd">"""Resource with an icon."""</span>
|
|
<span class="k">return</span> <span class="s2">"content"</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/fastmcp/icons_demo.py">examples/fastmcp/icons_demo.py</a></em></p>
|
|
<h3 id="images">Images</h3>
|
|
<p>FastMCP provides an <code>Image</code> class that automatically handles image data:</p>
|
|
<!-- snippet-source examples/snippets/servers/images.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""Example showing image handling with FastMCP."""</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">PIL</span><span class="w"> </span><span class="kn">import</span> <span class="n">Image</span> <span class="k">as</span> <span class="n">PILImage</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span><span class="p">,</span> <span class="n">Image</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Image Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">create_thumbnail</span><span class="p">(</span><span class="n">image_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">Image</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Create a thumbnail from an image"""</span>
|
|
<span class="n">img</span> <span class="o">=</span> <span class="n">PILImage</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">image_path</span><span class="p">)</span>
|
|
<span class="n">img</span><span class="o">.</span><span class="n">thumbnail</span><span class="p">((</span><span class="mi">100</span><span class="p">,</span> <span class="mi">100</span><span class="p">))</span>
|
|
<span class="k">return</span> <span class="n">Image</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">img</span><span class="o">.</span><span class="n">tobytes</span><span class="p">(),</span> <span class="nb">format</span><span class="o">=</span><span class="s2">"png"</span><span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/images.py">examples/snippets/servers/images.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h3 id="audio">Audio</h3>
|
|
<p>FastMCP provides an <code>Audio</code> class for returning audio data from tools, similar to <code>Image</code>:</p>
|
|
<!-- snippet-source examples/snippets/servers/audio_example.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp.utilities.types</span><span class="w"> </span><span class="kn">import</span> <span class="n">Audio</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Audio Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_audio_from_file</span><span class="p">(</span><span class="n">file_path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">Audio</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Return audio from a file path (format auto-detected from extension)."""</span>
|
|
<span class="k">return</span> <span class="n">Audio</span><span class="p">(</span><span class="n">path</span><span class="o">=</span><span class="n">file_path</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">get_audio_from_bytes</span><span class="p">(</span><span class="n">raw_audio</span><span class="p">:</span> <span class="nb">bytes</span><span class="p">)</span> <span class="o">-></span> <span class="n">Audio</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Return audio from raw bytes with explicit format."""</span>
|
|
<span class="k">return</span> <span class="n">Audio</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">raw_audio</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="s2">"wav"</span><span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/audio_example.py">examples/snippets/servers/audio_example.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<p>The <code>Audio</code> class accepts <code>path</code> or <code>data</code> (mutually exclusive) and an optional <code>format</code> string. Supported formats include <code>wav</code>, <code>mp3</code>, <code>ogg</code>, <code>flac</code>, <code>aac</code>, and <code>m4a</code>. When using a file path, the MIME type is inferred from the file extension.</p>
|
|
<h3 id="embedded-resource-results">Embedded Resource Results</h3>
|
|
<p>Tools can return <code>EmbeddedResource</code> to attach file contents or data inline in the result:</p>
|
|
<!-- snippet-source examples/snippets/servers/embedded_resource_results.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.types</span><span class="w"> </span><span class="kn">import</span> <span class="n">EmbeddedResource</span><span class="p">,</span> <span class="n">TextResourceContents</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Embedded Resource Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">read_config</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">EmbeddedResource</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Read a config file and return it as an embedded resource."""</span>
|
|
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
|
<span class="n">content</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
|
<span class="k">return</span> <span class="n">EmbeddedResource</span><span class="p">(</span>
|
|
<span class="nb">type</span><span class="o">=</span><span class="s2">"resource"</span><span class="p">,</span>
|
|
<span class="n">resource</span><span class="o">=</span><span class="n">TextResourceContents</span><span class="p">(</span>
|
|
<span class="n">uri</span><span class="o">=</span><span class="sa">f</span><span class="s2">"file://</span><span class="si">{</span><span class="n">path</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="n">text</span><span class="o">=</span><span class="n">content</span><span class="p">,</span>
|
|
<span class="n">mimeType</span><span class="o">=</span><span class="s2">"application/json"</span><span class="p">,</span>
|
|
<span class="p">),</span>
|
|
<span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/embedded_resource_results.py">examples/snippets/servers/embedded_resource_results.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<p>For binary embedded resources, use <code>BlobResourceContents</code> with base64-encoded data:</p>
|
|
<!-- snippet-source examples/snippets/servers/embedded_resource_results_binary.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">base64</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.types</span><span class="w"> </span><span class="kn">import</span> <span class="n">BlobResourceContents</span><span class="p">,</span> <span class="n">EmbeddedResource</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Binary Embedded Resource Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">read_binary_file</span><span class="p">(</span><span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">EmbeddedResource</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Read a binary file and return it as an embedded resource."""</span>
|
|
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s2">"rb"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
|
|
<span class="n">data</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">())</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
|
|
<span class="k">return</span> <span class="n">EmbeddedResource</span><span class="p">(</span>
|
|
<span class="nb">type</span><span class="o">=</span><span class="s2">"resource"</span><span class="p">,</span>
|
|
<span class="n">resource</span><span class="o">=</span><span class="n">BlobResourceContents</span><span class="p">(</span>
|
|
<span class="n">uri</span><span class="o">=</span><span class="sa">f</span><span class="s2">"file://</span><span class="si">{</span><span class="n">path</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="n">blob</span><span class="o">=</span><span class="n">data</span><span class="p">,</span>
|
|
<span class="n">mimeType</span><span class="o">=</span><span class="s2">"application/octet-stream"</span><span class="p">,</span>
|
|
<span class="p">),</span>
|
|
<span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/embedded_resource_results_binary.py">examples/snippets/servers/embedded_resource_results_binary.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h3 id="tool-change-notifications">Tool Change Notifications</h3>
|
|
<p>When your server dynamically adds or removes tools at runtime, notify connected clients so they can refresh their tool list:</p>
|
|
<!-- snippet-source examples/snippets/servers/tool_change_notifications.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.session</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServerSession</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Dynamic Tools"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">register_plugin</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="kc">None</span><span class="p">])</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Dynamically register a new tool and notify the client."""</span>
|
|
<span class="c1"># ... register the plugin's tools ...</span>
|
|
|
|
<span class="c1"># Notify the client that the tool list has changed</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">send_tool_list_changed</span><span class="p">()</span>
|
|
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Plugin '</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">' registered"</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/tool_change_notifications.py">examples/snippets/servers/tool_change_notifications.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h3 id="context">Context</h3>
|
|
<p>The Context object is automatically injected into tool and resource functions that request it via type hints. It provides access to MCP capabilities like logging, progress reporting, resource reading, user interaction, and request metadata.</p>
|
|
<h4 id="getting-context-in-functions">Getting Context in Functions</h4>
|
|
<p>To use context in a tool or resource function, add a parameter with the <code>Context</code> type annotation:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"Context Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">my_tool</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Tool that uses context capabilities."""</span>
|
|
<span class="c1"># The context parameter can have any name as long as it's type-annotated</span>
|
|
<span class="k">return</span> <span class="k">await</span> <span class="n">process_with_context</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">ctx</span><span class="p">)</span>
|
|
</code></pre></div>
|
|
<h4 id="context-properties-and-methods">Context Properties and Methods</h4>
|
|
<p>The Context object provides the following capabilities:</p>
|
|
<ul>
|
|
<li><code>ctx.request_id</code> - Unique ID for the current request</li>
|
|
<li><code>ctx.client_id</code> - Client ID if available</li>
|
|
<li><code>ctx.fastmcp</code> - Access to the FastMCP server instance (see <a href="#fastmcp-properties">FastMCP Properties</a>)</li>
|
|
<li><code>ctx.session</code> - Access to the underlying session for advanced communication (see <a href="#session-properties-and-methods">Session Properties and Methods</a>)</li>
|
|
<li><code>ctx.request_context</code> - Access to request-specific data and lifespan resources (see <a href="#request-context-properties">Request Context Properties</a>)</li>
|
|
<li><code>await ctx.debug(message)</code> - Send debug log message</li>
|
|
<li><code>await ctx.info(message)</code> - Send info log message</li>
|
|
<li><code>await ctx.warning(message)</code> - Send warning log message</li>
|
|
<li><code>await ctx.error(message)</code> - Send error log message</li>
|
|
<li><code>await ctx.log(level, message, logger_name=None)</code> - Send log with custom level</li>
|
|
<li><code>await ctx.report_progress(progress, total=None, message=None)</code> - Report operation progress</li>
|
|
<li><code>await ctx.read_resource(uri)</code> - Read a resource by URI</li>
|
|
<li><code>await ctx.elicit(message, schema)</code> - Request additional information from user with validation</li>
|
|
</ul>
|
|
<!-- snippet-source examples/snippets/servers/tool_progress.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.session</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServerSession</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"Progress Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">long_running_task</span><span class="p">(</span><span class="n">task_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="kc">None</span><span class="p">],</span> <span class="n">steps</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">5</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Execute a task with progress updates."""</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Starting: </span><span class="si">{</span><span class="n">task_name</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
|
|
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">steps</span><span class="p">):</span>
|
|
<span class="n">progress</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">/</span> <span class="n">steps</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">report_progress</span><span class="p">(</span>
|
|
<span class="n">progress</span><span class="o">=</span><span class="n">progress</span><span class="p">,</span>
|
|
<span class="n">total</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span>
|
|
<span class="n">message</span><span class="o">=</span><span class="sa">f</span><span class="s2">"Step </span><span class="si">{</span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">steps</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Completed step </span><span class="si">{</span><span class="n">i</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="mi">1</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Task '</span><span class="si">{</span><span class="n">task_name</span><span class="si">}</span><span class="s2">' completed"</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/tool_progress.py">examples/snippets/servers/tool_progress.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h3 id="completions">Completions</h3>
|
|
<p>MCP supports providing completion suggestions for prompt arguments and resource template parameters. With the context parameter, servers can provide completions based on previously resolved values:</p>
|
|
<p>Client usage:</p>
|
|
<!-- snippet-source examples/snippets/clients/completion_client.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""</span>
|
|
<span class="sd">cd to the `examples/snippets` directory and run:</span>
|
|
<span class="sd"> uv run completion-client</span>
|
|
<span class="sd">"""</span>
|
|
|
|
<span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
|
|
<span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">ClientSession</span><span class="p">,</span> <span class="n">StdioServerParameters</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.client.stdio</span><span class="w"> </span><span class="kn">import</span> <span class="n">stdio_client</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.types</span><span class="w"> </span><span class="kn">import</span> <span class="n">PromptReference</span><span class="p">,</span> <span class="n">ResourceTemplateReference</span>
|
|
|
|
<span class="c1"># Create server parameters for stdio connection</span>
|
|
<span class="n">server_params</span> <span class="o">=</span> <span class="n">StdioServerParameters</span><span class="p">(</span>
|
|
<span class="n">command</span><span class="o">=</span><span class="s2">"uv"</span><span class="p">,</span> <span class="c1"># Using uv to run the server</span>
|
|
<span class="n">args</span><span class="o">=</span><span class="p">[</span><span class="s2">"run"</span><span class="p">,</span> <span class="s2">"server"</span><span class="p">,</span> <span class="s2">"completion"</span><span class="p">,</span> <span class="s2">"stdio"</span><span class="p">],</span> <span class="c1"># Server with completion support</span>
|
|
<span class="n">env</span><span class="o">=</span><span class="p">{</span><span class="s2">"UV_INDEX"</span><span class="p">:</span> <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"UV_INDEX"</span><span class="p">,</span> <span class="s2">""</span><span class="p">)},</span>
|
|
<span class="p">)</span>
|
|
|
|
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">run</span><span class="p">():</span>
|
|
<span class="w"> </span><span class="sd">"""Run the completion client example."""</span>
|
|
<span class="k">async</span> <span class="k">with</span> <span class="n">stdio_client</span><span class="p">(</span><span class="n">server_params</span><span class="p">)</span> <span class="k">as</span> <span class="p">(</span><span class="n">read</span><span class="p">,</span> <span class="n">write</span><span class="p">):</span>
|
|
<span class="k">async</span> <span class="k">with</span> <span class="n">ClientSession</span><span class="p">(</span><span class="n">read</span><span class="p">,</span> <span class="n">write</span><span class="p">)</span> <span class="k">as</span> <span class="n">session</span><span class="p">:</span>
|
|
<span class="c1"># Initialize the connection</span>
|
|
<span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">initialize</span><span class="p">()</span>
|
|
|
|
<span class="c1"># List available resource templates</span>
|
|
<span class="n">templates</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_resource_templates</span><span class="p">()</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="s2">"Available resource templates:"</span><span class="p">)</span>
|
|
<span class="k">for</span> <span class="n">template</span> <span class="ow">in</span> <span class="n">templates</span><span class="o">.</span><span class="n">resourceTemplates</span><span class="p">:</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" - </span><span class="si">{</span><span class="n">template</span><span class="o">.</span><span class="n">uriTemplate</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
|
|
<span class="c1"># List available prompts</span>
|
|
<span class="n">prompts</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_prompts</span><span class="p">()</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Available prompts:"</span><span class="p">)</span>
|
|
<span class="k">for</span> <span class="n">prompt</span> <span class="ow">in</span> <span class="n">prompts</span><span class="o">.</span><span class="n">prompts</span><span class="p">:</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">" - </span><span class="si">{</span><span class="n">prompt</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Complete resource template arguments</span>
|
|
<span class="k">if</span> <span class="n">templates</span><span class="o">.</span><span class="n">resourceTemplates</span><span class="p">:</span>
|
|
<span class="n">template</span> <span class="o">=</span> <span class="n">templates</span><span class="o">.</span><span class="n">resourceTemplates</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Completing arguments for resource template: </span><span class="si">{</span><span class="n">template</span><span class="o">.</span><span class="n">uriTemplate</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Complete without context</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">complete</span><span class="p">(</span>
|
|
<span class="n">ref</span><span class="o">=</span><span class="n">ResourceTemplateReference</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">"ref/resource"</span><span class="p">,</span> <span class="n">uri</span><span class="o">=</span><span class="n">template</span><span class="o">.</span><span class="n">uriTemplate</span><span class="p">),</span>
|
|
<span class="n">argument</span><span class="o">=</span><span class="p">{</span><span class="s2">"name"</span><span class="p">:</span> <span class="s2">"owner"</span><span class="p">,</span> <span class="s2">"value"</span><span class="p">:</span> <span class="s2">"model"</span><span class="p">},</span>
|
|
<span class="p">)</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Completions for 'owner' starting with 'model': </span><span class="si">{</span><span class="n">result</span><span class="o">.</span><span class="n">completion</span><span class="o">.</span><span class="n">values</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Complete with context - repo suggestions based on owner</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">complete</span><span class="p">(</span>
|
|
<span class="n">ref</span><span class="o">=</span><span class="n">ResourceTemplateReference</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">"ref/resource"</span><span class="p">,</span> <span class="n">uri</span><span class="o">=</span><span class="n">template</span><span class="o">.</span><span class="n">uriTemplate</span><span class="p">),</span>
|
|
<span class="n">argument</span><span class="o">=</span><span class="p">{</span><span class="s2">"name"</span><span class="p">:</span> <span class="s2">"repo"</span><span class="p">,</span> <span class="s2">"value"</span><span class="p">:</span> <span class="s2">""</span><span class="p">},</span>
|
|
<span class="n">context_arguments</span><span class="o">=</span><span class="p">{</span><span class="s2">"owner"</span><span class="p">:</span> <span class="s2">"modelcontextprotocol"</span><span class="p">},</span>
|
|
<span class="p">)</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Completions for 'repo' with owner='modelcontextprotocol': </span><span class="si">{</span><span class="n">result</span><span class="o">.</span><span class="n">completion</span><span class="o">.</span><span class="n">values</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Complete prompt arguments</span>
|
|
<span class="k">if</span> <span class="n">prompts</span><span class="o">.</span><span class="n">prompts</span><span class="p">:</span>
|
|
<span class="n">prompt_name</span> <span class="o">=</span> <span class="n">prompts</span><span class="o">.</span><span class="n">prompts</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">name</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Completing arguments for prompt: </span><span class="si">{</span><span class="n">prompt_name</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
|
|
<span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">complete</span><span class="p">(</span>
|
|
<span class="n">ref</span><span class="o">=</span><span class="n">PromptReference</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">"ref/prompt"</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">prompt_name</span><span class="p">),</span>
|
|
<span class="n">argument</span><span class="o">=</span><span class="p">{</span><span class="s2">"name"</span><span class="p">:</span> <span class="s2">"style"</span><span class="p">,</span> <span class="s2">"value"</span><span class="p">:</span> <span class="s2">""</span><span class="p">},</span>
|
|
<span class="p">)</span>
|
|
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Completions for 'style' argument: </span><span class="si">{</span><span class="n">result</span><span class="o">.</span><span class="n">completion</span><span class="o">.</span><span class="n">values</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>
|
|
<span class="w"> </span><span class="sd">"""Entry point for the completion client."""</span>
|
|
<span class="n">asyncio</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">run</span><span class="p">())</span>
|
|
|
|
|
|
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
|
|
<span class="n">main</span><span class="p">()</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/clients/completion_client.py">examples/snippets/clients/completion_client.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
<h3 id="elicitation">Elicitation</h3>
|
|
<p>Request additional information from users. This example shows an Elicitation during a Tool Call:</p>
|
|
<!-- snippet-source examples/snippets/servers/elicitation.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""Elicitation examples demonstrating form and URL mode elicitation.</span>
|
|
|
|
<span class="sd">Form mode elicitation collects structured, non-sensitive data through a schema.</span>
|
|
<span class="sd">URL mode elicitation directs users to external URLs for sensitive operations</span>
|
|
<span class="sd">like OAuth flows, credential collection, or payment processing.</span>
|
|
<span class="sd">"""</span>
|
|
|
|
<span class="kn">import</span><span class="w"> </span><span class="nn">uuid</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">pydantic</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">Field</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.session</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServerSession</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.shared.exceptions</span><span class="w"> </span><span class="kn">import</span> <span class="n">UrlElicitationRequiredError</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.types</span><span class="w"> </span><span class="kn">import</span> <span class="n">ElicitRequestURLParams</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"Elicitation Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">BookingPreferences</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
|
|
<span class="w"> </span><span class="sd">"""Schema for collecting user preferences."""</span>
|
|
|
|
<span class="n">checkAlternative</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Would you like to check another date?"</span><span class="p">)</span>
|
|
<span class="n">alternativeDate</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span>
|
|
<span class="n">default</span><span class="o">=</span><span class="s2">"2024-12-26"</span><span class="p">,</span>
|
|
<span class="n">description</span><span class="o">=</span><span class="s2">"Alternative date (YYYY-MM-DD)"</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">book_table</span><span class="p">(</span><span class="n">date</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">time</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">party_size</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="kc">None</span><span class="p">])</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Book a table with date availability check.</span>
|
|
|
|
<span class="sd"> This demonstrates form mode elicitation for collecting non-sensitive user input.</span>
|
|
<span class="sd"> """</span>
|
|
<span class="c1"># Check if date is available</span>
|
|
<span class="k">if</span> <span class="n">date</span> <span class="o">==</span> <span class="s2">"2024-12-25"</span><span class="p">:</span>
|
|
<span class="c1"># Date unavailable - ask user for alternative</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">elicit</span><span class="p">(</span>
|
|
<span class="n">message</span><span class="o">=</span><span class="p">(</span><span class="sa">f</span><span class="s2">"No tables available for </span><span class="si">{</span><span class="n">party_size</span><span class="si">}</span><span class="s2"> on </span><span class="si">{</span><span class="n">date</span><span class="si">}</span><span class="s2">. Would you like to try another date?"</span><span class="p">),</span>
|
|
<span class="n">schema</span><span class="o">=</span><span class="n">BookingPreferences</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">action</span> <span class="o">==</span> <span class="s2">"accept"</span> <span class="ow">and</span> <span class="n">result</span><span class="o">.</span><span class="n">data</span><span class="p">:</span>
|
|
<span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">checkAlternative</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"[SUCCESS] Booked for </span><span class="si">{</span><span class="n">result</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">alternativeDate</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="k">return</span> <span class="s2">"[CANCELLED] No booking made"</span>
|
|
<span class="k">return</span> <span class="s2">"[CANCELLED] Booking cancelled"</span>
|
|
|
|
<span class="c1"># Date available</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"[SUCCESS] Booked for </span><span class="si">{</span><span class="n">date</span><span class="si">}</span><span class="s2"> at </span><span class="si">{</span><span class="n">time</span><span class="si">}</span><span class="s2">"</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">secure_payment</span><span class="p">(</span><span class="n">amount</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="kc">None</span><span class="p">])</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Process a secure payment requiring URL confirmation.</span>
|
|
|
|
<span class="sd"> This demonstrates URL mode elicitation using ctx.elicit_url() for</span>
|
|
<span class="sd"> operations that require out-of-band user interaction.</span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">elicitation_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid4</span><span class="p">())</span>
|
|
|
|
<span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">elicit_url</span><span class="p">(</span>
|
|
<span class="n">message</span><span class="o">=</span><span class="sa">f</span><span class="s2">"Please confirm payment of $</span><span class="si">{</span><span class="n">amount</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="n">url</span><span class="o">=</span><span class="sa">f</span><span class="s2">"https://payments.example.com/confirm?amount=</span><span class="si">{</span><span class="n">amount</span><span class="si">}</span><span class="s2">&id=</span><span class="si">{</span><span class="n">elicitation_id</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="n">elicitation_id</span><span class="o">=</span><span class="n">elicitation_id</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">action</span> <span class="o">==</span> <span class="s2">"accept"</span><span class="p">:</span>
|
|
<span class="c1"># In a real app, the payment confirmation would happen out-of-band</span>
|
|
<span class="c1"># and you'd verify the payment status from your backend</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Payment of $</span><span class="si">{</span><span class="n">amount</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2"> initiated - check your browser to complete"</span>
|
|
<span class="k">elif</span> <span class="n">result</span><span class="o">.</span><span class="n">action</span> <span class="o">==</span> <span class="s2">"decline"</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="s2">"Payment declined by user"</span>
|
|
<span class="k">return</span> <span class="s2">"Payment cancelled"</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">connect_service</span><span class="p">(</span><span class="n">service_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="kc">None</span><span class="p">])</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Connect to a third-party service requiring OAuth authorization.</span>
|
|
|
|
<span class="sd"> This demonstrates the "throw error" pattern using UrlElicitationRequiredError.</span>
|
|
<span class="sd"> Use this pattern when the tool cannot proceed without user authorization.</span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">elicitation_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid4</span><span class="p">())</span>
|
|
|
|
<span class="c1"># Raise UrlElicitationRequiredError to signal that the client must complete</span>
|
|
<span class="c1"># a URL elicitation before this request can be processed.</span>
|
|
<span class="c1"># The MCP framework will convert this to a -32042 error response.</span>
|
|
<span class="k">raise</span> <span class="n">UrlElicitationRequiredError</span><span class="p">(</span>
|
|
<span class="p">[</span>
|
|
<span class="n">ElicitRequestURLParams</span><span class="p">(</span>
|
|
<span class="n">mode</span><span class="o">=</span><span class="s2">"url"</span><span class="p">,</span>
|
|
<span class="n">message</span><span class="o">=</span><span class="sa">f</span><span class="s2">"Authorization required to connect to </span><span class="si">{</span><span class="n">service_name</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="n">url</span><span class="o">=</span><span class="sa">f</span><span class="s2">"https://</span><span class="si">{</span><span class="n">service_name</span><span class="si">}</span><span class="s2">.example.com/oauth/authorize?elicit=</span><span class="si">{</span><span class="n">elicitation_id</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
|
|
<span class="n">elicitationId</span><span class="o">=</span><span class="n">elicitation_id</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
<span class="p">]</span>
|
|
<span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/elicitation.py">examples/snippets/servers/elicitation.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<p>Elicitation schemas support default values for all field types. Default values are automatically included in the JSON schema sent to clients, allowing them to pre-populate forms.</p>
|
|
<p>The <code>elicit()</code> method returns an <code>ElicitationResult</code> with:</p>
|
|
<ul>
|
|
<li><code>action</code>: "accept", "decline", or "cancel"</li>
|
|
<li><code>data</code>: The validated response (only when accepted)</li>
|
|
</ul>
|
|
<h4 id="elicitation-with-enum-values">Elicitation with Enum Values</h4>
|
|
<p>To present a dropdown or selection list in elicitation forms, use <code>json_schema_extra</code> with an <code>enum</code> key on a <code>str</code> field. Do not use <code>Literal</code> -- use a plain <code>str</code> field with the enum constraint in the JSON schema:</p>
|
|
<!-- snippet-source examples/snippets/servers/elicitation_enum.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">pydantic</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">Field</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.session</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServerSession</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Enum Elicitation Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">ColorPreference</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
|
|
<span class="n">color</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Field</span><span class="p">(</span>
|
|
<span class="n">description</span><span class="o">=</span><span class="s2">"Pick your favorite color"</span><span class="p">,</span>
|
|
<span class="n">json_schema_extra</span><span class="o">=</span><span class="p">{</span><span class="s2">"enum"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"red"</span><span class="p">,</span> <span class="s2">"green"</span><span class="p">,</span> <span class="s2">"blue"</span><span class="p">,</span> <span class="s2">"yellow"</span><span class="p">]},</span>
|
|
<span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">pick_color</span><span class="p">(</span><span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="kc">None</span><span class="p">])</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Ask the user to pick a color from a list."""</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">elicit</span><span class="p">(</span>
|
|
<span class="n">message</span><span class="o">=</span><span class="s2">"Choose a color:"</span><span class="p">,</span>
|
|
<span class="n">schema</span><span class="o">=</span><span class="n">ColorPreference</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
<span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">action</span> <span class="o">==</span> <span class="s2">"accept"</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"You picked: </span><span class="si">{</span><span class="n">result</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">color</span><span class="si">}</span><span class="s2">"</span>
|
|
<span class="k">return</span> <span class="s2">"No color selected"</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/elicitation_enum.py">examples/snippets/servers/elicitation_enum.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h4 id="elicitation-complete-notification">Elicitation Complete Notification</h4>
|
|
<p>For URL mode elicitations, send a completion notification after the out-of-band interaction finishes. This tells the client that the elicitation is done and it may retry any blocked requests:</p>
|
|
<!-- snippet-source examples/snippets/servers/elicitation_complete.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.session</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServerSession</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Elicit Complete Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">handle_oauth_callback</span><span class="p">(</span><span class="n">elicitation_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="kc">None</span><span class="p">])</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Called when OAuth flow completes out-of-band."""</span>
|
|
<span class="c1"># ... process the callback ...</span>
|
|
|
|
<span class="c1"># Notify the client that the elicitation is done</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">send_elicit_complete</span><span class="p">(</span><span class="n">elicitation_id</span><span class="p">)</span>
|
|
|
|
<span class="k">return</span> <span class="s2">"Authorization complete"</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/elicitation_complete.py">examples/snippets/servers/elicitation_complete.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h3 id="sampling">Sampling</h3>
|
|
<p>Tools can interact with LLMs through sampling (generating text):</p>
|
|
<!-- snippet-source examples/snippets/servers/sampling.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.session</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServerSession</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.types</span><span class="w"> </span><span class="kn">import</span> <span class="n">SamplingMessage</span><span class="p">,</span> <span class="n">TextContent</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"Sampling Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">generate_poem</span><span class="p">(</span><span class="n">topic</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="kc">None</span><span class="p">])</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Generate a poem using LLM sampling."""</span>
|
|
<span class="n">prompt</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"Write a short poem about </span><span class="si">{</span><span class="n">topic</span><span class="si">}</span><span class="s2">"</span>
|
|
|
|
<span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">create_message</span><span class="p">(</span>
|
|
<span class="n">messages</span><span class="o">=</span><span class="p">[</span>
|
|
<span class="n">SamplingMessage</span><span class="p">(</span>
|
|
<span class="n">role</span><span class="o">=</span><span class="s2">"user"</span><span class="p">,</span>
|
|
<span class="n">content</span><span class="o">=</span><span class="n">TextContent</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">"text"</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="n">prompt</span><span class="p">),</span>
|
|
<span class="p">)</span>
|
|
<span class="p">],</span>
|
|
<span class="n">max_tokens</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="c1"># Since we're not passing tools param, result.content is single content</span>
|
|
<span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="s2">"text"</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="n">result</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">text</span>
|
|
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">content</span><span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/sampling.py">examples/snippets/servers/sampling.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h3 id="logging-and-notifications">Logging and Notifications</h3>
|
|
<p>Tools can send logs and notifications through the context:</p>
|
|
<!-- snippet-source examples/snippets/servers/notifications.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">Context</span><span class="p">,</span> <span class="n">FastMCP</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.session</span><span class="w"> </span><span class="kn">import</span> <span class="n">ServerSession</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"Notifications Example"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">process_data</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">[</span><span class="n">ServerSession</span><span class="p">,</span> <span class="kc">None</span><span class="p">])</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Process data with logging."""</span>
|
|
<span class="c1"># Different log levels</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Debug: Processing '</span><span class="si">{</span><span class="n">data</span><span class="si">}</span><span class="s2">'"</span><span class="p">)</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"Info: Starting processing"</span><span class="p">)</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s2">"Warning: This is experimental"</span><span class="p">)</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">"Error: (This is just a demo)"</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Notify about resource changes</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">send_resource_list_changed</span><span class="p">()</span>
|
|
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Processed: </span><span class="si">{</span><span class="n">data</span><span class="si">}</span><span class="s2">"</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/notifications.py">examples/snippets/servers/notifications.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h4 id="setting-the-logging-level">Setting the Logging Level</h4>
|
|
<p>Clients can request a minimum logging level via <code>logging/setLevel</code>. Use the low-level server API to handle this:</p>
|
|
<!-- snippet-source examples/snippets/servers/set_logging_level.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">import</span><span class="w"> </span><span class="nn">mcp.types</span><span class="w"> </span><span class="k">as</span><span class="w"> </span><span class="nn">types</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.lowlevel</span><span class="w"> </span><span class="kn">import</span> <span class="n">Server</span>
|
|
|
|
<span class="n">server</span> <span class="o">=</span> <span class="n">Server</span><span class="p">(</span><span class="s2">"Logging Level Example"</span><span class="p">)</span>
|
|
|
|
<span class="n">current_level</span><span class="p">:</span> <span class="n">types</span><span class="o">.</span><span class="n">LoggingLevel</span> <span class="o">=</span> <span class="s2">"warning"</span>
|
|
|
|
|
|
<span class="nd">@server</span><span class="o">.</span><span class="n">set_logging_level</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">handle_set_level</span><span class="p">(</span><span class="n">level</span><span class="p">:</span> <span class="n">types</span><span class="o">.</span><span class="n">LoggingLevel</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Handle client request to change the logging level."""</span>
|
|
<span class="k">global</span> <span class="n">current_level</span>
|
|
<span class="n">current_level</span> <span class="o">=</span> <span class="n">level</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/set_logging_level.py">examples/snippets/servers/set_logging_level.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<p>When this handler is registered, the server automatically declares the <code>logging</code> capability during initialization.</p>
|
|
<h3 id="authentication">Authentication</h3>
|
|
<p>For OAuth 2.1 server and client authentication, see <a href="../authorization/">Authorization</a>.</p>
|
|
<h3 id="fastmcp-properties">FastMCP Properties</h3>
|
|
<p>The FastMCP server instance accessible via <code>ctx.fastmcp</code> provides access to server configuration and metadata:</p>
|
|
<ul>
|
|
<li><code>ctx.fastmcp.name</code> - The server's name as defined during initialization</li>
|
|
<li><code>ctx.fastmcp.instructions</code> - Server instructions/description provided to clients</li>
|
|
<li><code>ctx.fastmcp.website_url</code> - Optional website URL for the server</li>
|
|
<li><code>ctx.fastmcp.icons</code> - Optional list of icons for UI display</li>
|
|
<li><code>ctx.fastmcp.settings</code> - Complete server configuration object containing:</li>
|
|
<li><code>debug</code> - Debug mode flag</li>
|
|
<li><code>log_level</code> - Current logging level</li>
|
|
<li><code>host</code> and <code>port</code> - Server network configuration</li>
|
|
<li><code>mount_path</code>, <code>sse_path</code>, <code>streamable_http_path</code> - Transport paths</li>
|
|
<li><code>stateless_http</code> - Whether the server operates in stateless mode</li>
|
|
<li>And other configuration options</li>
|
|
</ul>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">server_info</span><span class="p">(</span><span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">)</span> <span class="o">-></span> <span class="nb">dict</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Get information about the current server."""</span>
|
|
<span class="k">return</span> <span class="p">{</span>
|
|
<span class="s2">"name"</span><span class="p">:</span> <span class="n">ctx</span><span class="o">.</span><span class="n">fastmcp</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
|
|
<span class="s2">"instructions"</span><span class="p">:</span> <span class="n">ctx</span><span class="o">.</span><span class="n">fastmcp</span><span class="o">.</span><span class="n">instructions</span><span class="p">,</span>
|
|
<span class="s2">"debug_mode"</span><span class="p">:</span> <span class="n">ctx</span><span class="o">.</span><span class="n">fastmcp</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">debug</span><span class="p">,</span>
|
|
<span class="s2">"log_level"</span><span class="p">:</span> <span class="n">ctx</span><span class="o">.</span><span class="n">fastmcp</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">log_level</span><span class="p">,</span>
|
|
<span class="s2">"host"</span><span class="p">:</span> <span class="n">ctx</span><span class="o">.</span><span class="n">fastmcp</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">host</span><span class="p">,</span>
|
|
<span class="s2">"port"</span><span class="p">:</span> <span class="n">ctx</span><span class="o">.</span><span class="n">fastmcp</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">port</span><span class="p">,</span>
|
|
<span class="p">}</span>
|
|
</code></pre></div>
|
|
<h3 id="session-properties-and-methods">Session Properties and Methods</h3>
|
|
<p>The session object accessible via <code>ctx.session</code> provides advanced control over client communication:</p>
|
|
<ul>
|
|
<li><code>ctx.session.client_params</code> - Client initialization parameters and declared capabilities</li>
|
|
<li><code>await ctx.session.send_log_message(level, data, logger)</code> - Send log messages with full control</li>
|
|
<li><code>await ctx.session.create_message(messages, max_tokens)</code> - Request LLM sampling/completion</li>
|
|
<li><code>await ctx.session.send_progress_notification(token, progress, total, message)</code> - Direct progress updates</li>
|
|
<li><code>await ctx.session.send_resource_updated(uri)</code> - Notify clients that a specific resource changed</li>
|
|
<li><code>await ctx.session.send_resource_list_changed()</code> - Notify clients that the resource list changed</li>
|
|
<li><code>await ctx.session.send_tool_list_changed()</code> - Notify clients that the tool list changed</li>
|
|
<li><code>await ctx.session.send_prompt_list_changed()</code> - Notify clients that the prompt list changed</li>
|
|
</ul>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">notify_data_update</span><span class="p">(</span><span class="n">resource_uri</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Update data and notify clients of the change."""</span>
|
|
<span class="c1"># Perform data update logic here</span>
|
|
|
|
<span class="c1"># Notify clients that this specific resource changed</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">send_resource_updated</span><span class="p">(</span><span class="n">AnyUrl</span><span class="p">(</span><span class="n">resource_uri</span><span class="p">))</span>
|
|
|
|
<span class="c1"># If this affects the overall resource list, notify about that too</span>
|
|
<span class="k">await</span> <span class="n">ctx</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">send_resource_list_changed</span><span class="p">()</span>
|
|
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Updated </span><span class="si">{</span><span class="n">resource_uri</span><span class="si">}</span><span class="s2"> and notified clients"</span>
|
|
</code></pre></div>
|
|
<h3 id="request-context-properties">Request Context Properties</h3>
|
|
<p>The request context accessible via <code>ctx.request_context</code> contains request-specific information and resources:</p>
|
|
<ul>
|
|
<li><code>ctx.request_context.lifespan_context</code> - Access to resources initialized during server startup</li>
|
|
<li>Database connections, configuration objects, shared services</li>
|
|
<li>Type-safe access to resources defined in your server's lifespan function</li>
|
|
<li><code>ctx.request_context.meta</code> - Request metadata from the client including:</li>
|
|
<li><code>progressToken</code> - Token for progress notifications</li>
|
|
<li>Other client-provided metadata</li>
|
|
<li><code>ctx.request_context.request</code> - The original MCP request object for advanced processing</li>
|
|
<li><code>ctx.request_context.request_id</code> - Unique identifier for this request</li>
|
|
</ul>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="c1"># Example with typed lifespan context</span>
|
|
<span class="nd">@dataclass</span>
|
|
<span class="k">class</span><span class="w"> </span><span class="nc">AppContext</span><span class="p">:</span>
|
|
<span class="n">db</span><span class="p">:</span> <span class="n">Database</span>
|
|
<span class="n">config</span><span class="p">:</span> <span class="n">AppConfig</span>
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">query_with_config</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">ctx</span><span class="p">:</span> <span class="n">Context</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Execute a query using shared database and configuration."""</span>
|
|
<span class="c1"># Access typed lifespan context</span>
|
|
<span class="n">app_ctx</span><span class="p">:</span> <span class="n">AppContext</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">.</span><span class="n">request_context</span><span class="o">.</span><span class="n">lifespan_context</span>
|
|
|
|
<span class="c1"># Use shared resources</span>
|
|
<span class="n">connection</span> <span class="o">=</span> <span class="n">app_ctx</span><span class="o">.</span><span class="n">db</span>
|
|
<span class="n">settings</span> <span class="o">=</span> <span class="n">app_ctx</span><span class="o">.</span><span class="n">config</span>
|
|
|
|
<span class="c1"># Execute query with configuration</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="n">connection</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="n">settings</span><span class="o">.</span><span class="n">query_timeout</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full lifespan example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/lifespan_example.py">examples/snippets/servers/lifespan_example.py</a></em></p>
|
|
<h2 id="running-your-server">Running Your Server</h2>
|
|
<h3 id="development-mode">Development Mode</h3>
|
|
<p>The fastest way to test and debug your server is with the MCP Inspector:</p>
|
|
<div class="language-bash highlight"><pre><span></span><code>uv<span class="w"> </span>run<span class="w"> </span>mcp<span class="w"> </span>dev<span class="w"> </span>server.py
|
|
|
|
<span class="c1"># Add dependencies</span>
|
|
uv<span class="w"> </span>run<span class="w"> </span>mcp<span class="w"> </span>dev<span class="w"> </span>server.py<span class="w"> </span>--with<span class="w"> </span>pandas<span class="w"> </span>--with<span class="w"> </span>numpy
|
|
|
|
<span class="c1"># Mount local code</span>
|
|
uv<span class="w"> </span>run<span class="w"> </span>mcp<span class="w"> </span>dev<span class="w"> </span>server.py<span class="w"> </span>--with-editable<span class="w"> </span>.
|
|
</code></pre></div>
|
|
<h3 id="claude-desktop-integration">Claude Desktop Integration</h3>
|
|
<p>Once your server is ready, install it in Claude Desktop:</p>
|
|
<div class="language-bash highlight"><pre><span></span><code>uv<span class="w"> </span>run<span class="w"> </span>mcp<span class="w"> </span>install<span class="w"> </span>server.py
|
|
|
|
<span class="c1"># Custom name</span>
|
|
uv<span class="w"> </span>run<span class="w"> </span>mcp<span class="w"> </span>install<span class="w"> </span>server.py<span class="w"> </span>--name<span class="w"> </span><span class="s2">"My Analytics Server"</span>
|
|
|
|
<span class="c1"># Environment variables</span>
|
|
uv<span class="w"> </span>run<span class="w"> </span>mcp<span class="w"> </span>install<span class="w"> </span>server.py<span class="w"> </span>-v<span class="w"> </span><span class="nv">API_KEY</span><span class="o">=</span>abc123<span class="w"> </span>-v<span class="w"> </span><span class="nv">DB_URL</span><span class="o">=</span>postgres://...
|
|
uv<span class="w"> </span>run<span class="w"> </span>mcp<span class="w"> </span>install<span class="w"> </span>server.py<span class="w"> </span>-f<span class="w"> </span>.env
|
|
</code></pre></div>
|
|
<h3 id="direct-execution">Direct Execution</h3>
|
|
<p>For advanced scenarios like custom deployments:</p>
|
|
<!-- snippet-source examples/snippets/servers/direct_execution.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""Example showing direct execution of an MCP server.</span>
|
|
|
|
<span class="sd">This is the simplest way to run an MCP server directly.</span>
|
|
<span class="sd">cd to the `examples/snippets` directory and run:</span>
|
|
<span class="sd"> uv run direct-execution-server</span>
|
|
<span class="sd"> or</span>
|
|
<span class="sd"> python servers/direct_execution.py</span>
|
|
<span class="sd">"""</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"My App"</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">hello</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">"World"</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Say hello to someone."""</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Hello, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">!"</span>
|
|
|
|
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">main</span><span class="p">():</span>
|
|
<span class="w"> </span><span class="sd">"""Entry point for the direct execution server."""</span>
|
|
<span class="n">mcp</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
|
|
|
|
|
|
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
|
|
<span class="n">main</span><span class="p">()</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/direct_execution.py">examples/snippets/servers/direct_execution.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<p>Run it with:</p>
|
|
<div class="language-bash highlight"><pre><span></span><code>python<span class="w"> </span>servers/direct_execution.py
|
|
<span class="c1"># or</span>
|
|
uv<span class="w"> </span>run<span class="w"> </span>mcp<span class="w"> </span>run<span class="w"> </span>servers/direct_execution.py
|
|
</code></pre></div>
|
|
<p>Note that <code>uv run mcp run</code> or <code>uv run mcp dev</code> only supports server using FastMCP and not the low-level server variant.</p>
|
|
<h3 id="streamable-http-transport">Streamable HTTP Transport</h3>
|
|
<blockquote>
|
|
<p><strong>Note</strong>: Streamable HTTP transport is the recommended transport for production deployments. Use <code>stateless_http=True</code> and <code>json_response=True</code> for optimal scalability.</p>
|
|
</blockquote>
|
|
<!-- snippet-source examples/snippets/servers/streamable_config.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""</span>
|
|
<span class="sd">Run from the repository root:</span>
|
|
<span class="sd"> uv run examples/snippets/servers/streamable_config.py</span>
|
|
<span class="sd">"""</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="c1"># Stateless server with JSON responses (recommended)</span>
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"StatelessServer"</span><span class="p">,</span> <span class="n">stateless_http</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">json_response</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Other configuration options:</span>
|
|
<span class="c1"># Stateless server with SSE streaming responses</span>
|
|
<span class="c1"># mcp = FastMCP("StatelessServer", stateless_http=True)</span>
|
|
|
|
<span class="c1"># Stateful server with session persistence</span>
|
|
<span class="c1"># mcp = FastMCP("StatefulServer")</span>
|
|
|
|
|
|
<span class="c1"># Add a simple tool to demonstrate the server</span>
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">greet</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">"World"</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Greet someone by name."""</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Hello, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">!"</span>
|
|
|
|
|
|
<span class="c1"># Run server with streamable_http transport</span>
|
|
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
|
|
<span class="n">mcp</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">transport</span><span class="o">=</span><span class="s2">"streamable-http"</span><span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/streamable_config.py">examples/snippets/servers/streamable_config.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<p>You can mount multiple FastMCP servers in a Starlette application:</p>
|
|
<!-- snippet-source examples/snippets/servers/streamable_starlette_mount.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""</span>
|
|
<span class="sd">Run from the repository root:</span>
|
|
<span class="sd"> uvicorn examples.snippets.servers.streamable_starlette_mount:app --reload</span>
|
|
<span class="sd">"""</span>
|
|
|
|
<span class="kn">import</span><span class="w"> </span><span class="nn">contextlib</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.applications</span><span class="w"> </span><span class="kn">import</span> <span class="n">Starlette</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.routing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Mount</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="c1"># Create the Echo server</span>
|
|
<span class="n">echo_mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"EchoServer"</span><span class="p">,</span> <span class="n">stateless_http</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">json_response</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@echo_mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">echo</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""A simple echo tool"""</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Echo: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">"</span>
|
|
|
|
|
|
<span class="c1"># Create the Math server</span>
|
|
<span class="n">math_mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s2">"MathServer"</span><span class="p">,</span> <span class="n">stateless_http</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">json_response</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@math_mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">add_two</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-></span> <span class="nb">int</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Tool to add two to the input"""</span>
|
|
<span class="k">return</span> <span class="n">n</span> <span class="o">+</span> <span class="mi">2</span>
|
|
|
|
|
|
<span class="c1"># Create a combined lifespan to manage both session managers</span>
|
|
<span class="nd">@contextlib</span><span class="o">.</span><span class="n">asynccontextmanager</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">lifespan</span><span class="p">(</span><span class="n">app</span><span class="p">:</span> <span class="n">Starlette</span><span class="p">):</span>
|
|
<span class="k">async</span> <span class="k">with</span> <span class="n">contextlib</span><span class="o">.</span><span class="n">AsyncExitStack</span><span class="p">()</span> <span class="k">as</span> <span class="n">stack</span><span class="p">:</span>
|
|
<span class="k">await</span> <span class="n">stack</span><span class="o">.</span><span class="n">enter_async_context</span><span class="p">(</span><span class="n">echo_mcp</span><span class="o">.</span><span class="n">session_manager</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
|
|
<span class="k">await</span> <span class="n">stack</span><span class="o">.</span><span class="n">enter_async_context</span><span class="p">(</span><span class="n">math_mcp</span><span class="o">.</span><span class="n">session_manager</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
|
|
<span class="k">yield</span>
|
|
|
|
|
|
<span class="c1"># Create the Starlette app and mount the MCP servers</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="n">Starlette</span><span class="p">(</span>
|
|
<span class="n">routes</span><span class="o">=</span><span class="p">[</span>
|
|
<span class="n">Mount</span><span class="p">(</span><span class="s2">"/echo"</span><span class="p">,</span> <span class="n">echo_mcp</span><span class="o">.</span><span class="n">streamable_http_app</span><span class="p">()),</span>
|
|
<span class="n">Mount</span><span class="p">(</span><span class="s2">"/math"</span><span class="p">,</span> <span class="n">math_mcp</span><span class="o">.</span><span class="n">streamable_http_app</span><span class="p">()),</span>
|
|
<span class="p">],</span>
|
|
<span class="n">lifespan</span><span class="o">=</span><span class="n">lifespan</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="c1"># Note: Clients connect to http://localhost:8000/echo/mcp and http://localhost:8000/math/mcp</span>
|
|
<span class="c1"># To mount at the root of each path (e.g., /echo instead of /echo/mcp):</span>
|
|
<span class="c1"># echo_mcp.settings.streamable_http_path = "/"</span>
|
|
<span class="c1"># math_mcp.settings.streamable_http_path = "/"</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/streamable_starlette_mount.py">examples/snippets/servers/streamable_starlette_mount.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<p>For low level server with Streamable HTTP implementations, see:</p>
|
|
<ul>
|
|
<li>Stateful server: <a href="https://github.com/modelcontextprotocol/python-sdk/tree/v1.x/examples/servers/simple-streamablehttp"><code>examples/servers/simple-streamablehttp/</code></a></li>
|
|
<li>Stateless server: <a href="https://github.com/modelcontextprotocol/python-sdk/tree/v1.x/examples/servers/simple-streamablehttp-stateless"><code>examples/servers/simple-streamablehttp-stateless/</code></a></li>
|
|
</ul>
|
|
<p>The streamable HTTP transport supports:</p>
|
|
<ul>
|
|
<li>Stateful and stateless operation modes</li>
|
|
<li>Resumability with event stores</li>
|
|
<li>JSON or SSE response formats</li>
|
|
<li>Better scalability for multi-node deployments</li>
|
|
</ul>
|
|
<h4 id="cors-configuration-for-browser-based-clients">CORS Configuration for Browser-Based Clients</h4>
|
|
<p>If you'd like your server to be accessible by browser-based MCP clients, you'll need to configure CORS headers. The <code>Mcp-Session-Id</code> header must be exposed for browser clients to access it:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">starlette.applications</span><span class="w"> </span><span class="kn">import</span> <span class="n">Starlette</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.middleware.cors</span><span class="w"> </span><span class="kn">import</span> <span class="n">CORSMiddleware</span>
|
|
|
|
<span class="c1"># Create your Starlette app first</span>
|
|
<span class="n">starlette_app</span> <span class="o">=</span> <span class="n">Starlette</span><span class="p">(</span><span class="n">routes</span><span class="o">=</span><span class="p">[</span><span class="o">...</span><span class="p">])</span>
|
|
|
|
<span class="c1"># Then wrap it with CORS middleware</span>
|
|
<span class="n">starlette_app</span> <span class="o">=</span> <span class="n">CORSMiddleware</span><span class="p">(</span>
|
|
<span class="n">starlette_app</span><span class="p">,</span>
|
|
<span class="n">allow_origins</span><span class="o">=</span><span class="p">[</span><span class="s2">"*"</span><span class="p">],</span> <span class="c1"># Configure appropriately for production</span>
|
|
<span class="n">allow_methods</span><span class="o">=</span><span class="p">[</span><span class="s2">"GET"</span><span class="p">,</span> <span class="s2">"POST"</span><span class="p">,</span> <span class="s2">"DELETE"</span><span class="p">],</span> <span class="c1"># MCP streamable HTTP methods</span>
|
|
<span class="n">expose_headers</span><span class="o">=</span><span class="p">[</span><span class="s2">"Mcp-Session-Id"</span><span class="p">],</span>
|
|
<span class="p">)</span>
|
|
</code></pre></div>
|
|
<p>This configuration is necessary because:</p>
|
|
<ul>
|
|
<li>The MCP streamable HTTP transport uses the <code>Mcp-Session-Id</code> header for session management</li>
|
|
<li>Browsers restrict access to response headers unless explicitly exposed via CORS</li>
|
|
<li>Without this configuration, browser-based clients won't be able to read the session ID from initialization responses</li>
|
|
</ul>
|
|
<h3 id="mounting-to-an-existing-asgi-server">Mounting to an Existing ASGI Server</h3>
|
|
<p>By default, SSE servers are mounted at <code>/sse</code> and Streamable HTTP servers are mounted at <code>/mcp</code>. You can customize these paths using the methods described below.</p>
|
|
<p>For more information on mounting applications in Starlette, see the <a href="https://www.starlette.io/routing/#submounting-routes">Starlette documentation</a>.</p>
|
|
<h4 id="streamablehttp-servers">StreamableHTTP servers</h4>
|
|
<p>You can mount the StreamableHTTP server to an existing ASGI server using the <code>streamable_http_app</code> method. This allows you to integrate the StreamableHTTP server with other ASGI applications.</p>
|
|
<h5 id="basic-mounting">Basic mounting</h5>
|
|
<!-- snippet-source examples/snippets/servers/streamable_http_basic_mounting.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""</span>
|
|
<span class="sd">Basic example showing how to mount StreamableHTTP server in Starlette.</span>
|
|
|
|
<span class="sd">Run from the repository root:</span>
|
|
<span class="sd"> uvicorn examples.snippets.servers.streamable_http_basic_mounting:app --reload</span>
|
|
<span class="sd">"""</span>
|
|
|
|
<span class="kn">import</span><span class="w"> </span><span class="nn">contextlib</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.applications</span><span class="w"> </span><span class="kn">import</span> <span class="n">Starlette</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.routing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Mount</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="c1"># Create MCP server</span>
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"My App"</span><span class="p">,</span> <span class="n">json_response</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">hello</span><span class="p">()</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""A simple hello tool"""</span>
|
|
<span class="k">return</span> <span class="s2">"Hello from MCP!"</span>
|
|
|
|
|
|
<span class="c1"># Create a lifespan context manager to run the session manager</span>
|
|
<span class="nd">@contextlib</span><span class="o">.</span><span class="n">asynccontextmanager</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">lifespan</span><span class="p">(</span><span class="n">app</span><span class="p">:</span> <span class="n">Starlette</span><span class="p">):</span>
|
|
<span class="k">async</span> <span class="k">with</span> <span class="n">mcp</span><span class="o">.</span><span class="n">session_manager</span><span class="o">.</span><span class="n">run</span><span class="p">():</span>
|
|
<span class="k">yield</span>
|
|
|
|
|
|
<span class="c1"># Mount the StreamableHTTP server to the existing ASGI server</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="n">Starlette</span><span class="p">(</span>
|
|
<span class="n">routes</span><span class="o">=</span><span class="p">[</span>
|
|
<span class="n">Mount</span><span class="p">(</span><span class="s2">"/"</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="n">mcp</span><span class="o">.</span><span class="n">streamable_http_app</span><span class="p">()),</span>
|
|
<span class="p">],</span>
|
|
<span class="n">lifespan</span><span class="o">=</span><span class="n">lifespan</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/streamable_http_basic_mounting.py">examples/snippets/servers/streamable_http_basic_mounting.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h5 id="host-based-routing">Host-based routing</h5>
|
|
<!-- snippet-source examples/snippets/servers/streamable_http_host_mounting.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""</span>
|
|
<span class="sd">Example showing how to mount StreamableHTTP server using Host-based routing.</span>
|
|
|
|
<span class="sd">Run from the repository root:</span>
|
|
<span class="sd"> uvicorn examples.snippets.servers.streamable_http_host_mounting:app --reload</span>
|
|
<span class="sd">"""</span>
|
|
|
|
<span class="kn">import</span><span class="w"> </span><span class="nn">contextlib</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.applications</span><span class="w"> </span><span class="kn">import</span> <span class="n">Starlette</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.routing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Host</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="c1"># Create MCP server</span>
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"MCP Host App"</span><span class="p">,</span> <span class="n">json_response</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">domain_info</span><span class="p">()</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Get domain-specific information"""</span>
|
|
<span class="k">return</span> <span class="s2">"This is served from mcp.acme.corp"</span>
|
|
|
|
|
|
<span class="c1"># Create a lifespan context manager to run the session manager</span>
|
|
<span class="nd">@contextlib</span><span class="o">.</span><span class="n">asynccontextmanager</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">lifespan</span><span class="p">(</span><span class="n">app</span><span class="p">:</span> <span class="n">Starlette</span><span class="p">):</span>
|
|
<span class="k">async</span> <span class="k">with</span> <span class="n">mcp</span><span class="o">.</span><span class="n">session_manager</span><span class="o">.</span><span class="n">run</span><span class="p">():</span>
|
|
<span class="k">yield</span>
|
|
|
|
|
|
<span class="c1"># Mount using Host-based routing</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="n">Starlette</span><span class="p">(</span>
|
|
<span class="n">routes</span><span class="o">=</span><span class="p">[</span>
|
|
<span class="n">Host</span><span class="p">(</span><span class="s2">"mcp.acme.corp"</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="n">mcp</span><span class="o">.</span><span class="n">streamable_http_app</span><span class="p">()),</span>
|
|
<span class="p">],</span>
|
|
<span class="n">lifespan</span><span class="o">=</span><span class="n">lifespan</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/streamable_http_host_mounting.py">examples/snippets/servers/streamable_http_host_mounting.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h5 id="multiple-servers-with-path-configuration">Multiple servers with path configuration</h5>
|
|
<!-- snippet-source examples/snippets/servers/streamable_http_multiple_servers.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""</span>
|
|
<span class="sd">Example showing how to mount multiple StreamableHTTP servers with path configuration.</span>
|
|
|
|
<span class="sd">Run from the repository root:</span>
|
|
<span class="sd"> uvicorn examples.snippets.servers.streamable_http_multiple_servers:app --reload</span>
|
|
<span class="sd">"""</span>
|
|
|
|
<span class="kn">import</span><span class="w"> </span><span class="nn">contextlib</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.applications</span><span class="w"> </span><span class="kn">import</span> <span class="n">Starlette</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.routing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Mount</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="c1"># Create multiple MCP servers</span>
|
|
<span class="n">api_mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"API Server"</span><span class="p">,</span> <span class="n">json_response</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
<span class="n">chat_mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Chat Server"</span><span class="p">,</span> <span class="n">json_response</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@api_mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">api_status</span><span class="p">()</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Get API status"""</span>
|
|
<span class="k">return</span> <span class="s2">"API is running"</span>
|
|
|
|
|
|
<span class="nd">@chat_mcp</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">send_message</span><span class="p">(</span><span class="n">message</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Send a chat message"""</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Message sent: </span><span class="si">{</span><span class="n">message</span><span class="si">}</span><span class="s2">"</span>
|
|
|
|
|
|
<span class="c1"># Configure servers to mount at the root of each path</span>
|
|
<span class="c1"># This means endpoints will be at /api and /chat instead of /api/mcp and /chat/mcp</span>
|
|
<span class="n">api_mcp</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">streamable_http_path</span> <span class="o">=</span> <span class="s2">"/"</span>
|
|
<span class="n">chat_mcp</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">streamable_http_path</span> <span class="o">=</span> <span class="s2">"/"</span>
|
|
|
|
|
|
<span class="c1"># Create a combined lifespan to manage both session managers</span>
|
|
<span class="nd">@contextlib</span><span class="o">.</span><span class="n">asynccontextmanager</span>
|
|
<span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">lifespan</span><span class="p">(</span><span class="n">app</span><span class="p">:</span> <span class="n">Starlette</span><span class="p">):</span>
|
|
<span class="k">async</span> <span class="k">with</span> <span class="n">contextlib</span><span class="o">.</span><span class="n">AsyncExitStack</span><span class="p">()</span> <span class="k">as</span> <span class="n">stack</span><span class="p">:</span>
|
|
<span class="k">await</span> <span class="n">stack</span><span class="o">.</span><span class="n">enter_async_context</span><span class="p">(</span><span class="n">api_mcp</span><span class="o">.</span><span class="n">session_manager</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
|
|
<span class="k">await</span> <span class="n">stack</span><span class="o">.</span><span class="n">enter_async_context</span><span class="p">(</span><span class="n">chat_mcp</span><span class="o">.</span><span class="n">session_manager</span><span class="o">.</span><span class="n">run</span><span class="p">())</span>
|
|
<span class="k">yield</span>
|
|
|
|
|
|
<span class="c1"># Mount the servers</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="n">Starlette</span><span class="p">(</span>
|
|
<span class="n">routes</span><span class="o">=</span><span class="p">[</span>
|
|
<span class="n">Mount</span><span class="p">(</span><span class="s2">"/api"</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="n">api_mcp</span><span class="o">.</span><span class="n">streamable_http_app</span><span class="p">()),</span>
|
|
<span class="n">Mount</span><span class="p">(</span><span class="s2">"/chat"</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="n">chat_mcp</span><span class="o">.</span><span class="n">streamable_http_app</span><span class="p">()),</span>
|
|
<span class="p">],</span>
|
|
<span class="n">lifespan</span><span class="o">=</span><span class="n">lifespan</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/streamable_http_multiple_servers.py">examples/snippets/servers/streamable_http_multiple_servers.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h5 id="path-configuration-at-initialization">Path configuration at initialization</h5>
|
|
<!-- snippet-source examples/snippets/servers/streamable_http_path_config.py -->
|
|
<div class="language-python highlight"><pre><span></span><code><span class="sd">"""</span>
|
|
<span class="sd">Example showing path configuration during FastMCP initialization.</span>
|
|
|
|
<span class="sd">Run from the repository root:</span>
|
|
<span class="sd"> uvicorn examples.snippets.servers.streamable_http_path_config:app --reload</span>
|
|
<span class="sd">"""</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.applications</span><span class="w"> </span><span class="kn">import</span> <span class="n">Starlette</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.routing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Mount</span>
|
|
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="c1"># Configure streamable_http_path during initialization</span>
|
|
<span class="c1"># This server will mount at the root of wherever it's mounted</span>
|
|
<span class="n">mcp_at_root</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span>
|
|
<span class="s2">"My Server"</span><span class="p">,</span>
|
|
<span class="n">json_response</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
|
<span class="n">streamable_http_path</span><span class="o">=</span><span class="s2">"/"</span><span class="p">,</span>
|
|
<span class="p">)</span>
|
|
|
|
|
|
<span class="nd">@mcp_at_root</span><span class="o">.</span><span class="n">tool</span><span class="p">()</span>
|
|
<span class="k">def</span><span class="w"> </span><span class="nf">process_data</span><span class="p">(</span><span class="n">data</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
|
|
<span class="w"> </span><span class="sd">"""Process some data"""</span>
|
|
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Processed: </span><span class="si">{</span><span class="n">data</span><span class="si">}</span><span class="s2">"</span>
|
|
|
|
|
|
<span class="c1"># Mount at /process - endpoints will be at /process instead of /process/mcp</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="n">Starlette</span><span class="p">(</span>
|
|
<span class="n">routes</span><span class="o">=</span><span class="p">[</span>
|
|
<span class="n">Mount</span><span class="p">(</span><span class="s2">"/process"</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="n">mcp_at_root</span><span class="o">.</span><span class="n">streamable_http_app</span><span class="p">()),</span>
|
|
<span class="p">]</span>
|
|
<span class="p">)</span>
|
|
</code></pre></div>
|
|
<p><em>Full example: <a href="https://github.com/modelcontextprotocol/python-sdk/blob/v1.x/examples/snippets/servers/streamable_http_path_config.py">examples/snippets/servers/streamable_http_path_config.py</a></em></p>
|
|
<!-- /snippet-source -->
|
|
|
|
<h4 id="sse-servers">SSE servers</h4>
|
|
<blockquote>
|
|
<p><strong>Note</strong>: SSE transport is being superseded by <a href="https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#streamable-http">Streamable HTTP transport</a>.</p>
|
|
</blockquote>
|
|
<p>You can mount the SSE server to an existing ASGI server using the <code>sse_app</code> method. This allows you to integrate the SSE server with other ASGI applications.</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">starlette.applications</span><span class="w"> </span><span class="kn">import</span> <span class="n">Starlette</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.routing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Mount</span><span class="p">,</span> <span class="n">Host</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
|
|
<span class="n">mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"My App"</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Mount the SSE server to the existing ASGI server</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="n">Starlette</span><span class="p">(</span>
|
|
<span class="n">routes</span><span class="o">=</span><span class="p">[</span>
|
|
<span class="n">Mount</span><span class="p">(</span><span class="s1">'/'</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="n">mcp</span><span class="o">.</span><span class="n">sse_app</span><span class="p">()),</span>
|
|
<span class="p">]</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="c1"># or dynamically mount as host</span>
|
|
<span class="n">app</span><span class="o">.</span><span class="n">router</span><span class="o">.</span><span class="n">routes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">Host</span><span class="p">(</span><span class="s1">'mcp.acme.corp'</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="n">mcp</span><span class="o">.</span><span class="n">sse_app</span><span class="p">()))</span>
|
|
</code></pre></div>
|
|
<p>When mounting multiple MCP servers under different paths, you can configure the mount path in several ways:</p>
|
|
<div class="language-python highlight"><pre><span></span><code><span class="kn">from</span><span class="w"> </span><span class="nn">starlette.applications</span><span class="w"> </span><span class="kn">import</span> <span class="n">Starlette</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">starlette.routing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Mount</span>
|
|
<span class="kn">from</span><span class="w"> </span><span class="nn">mcp.server.fastmcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">FastMCP</span>
|
|
|
|
<span class="c1"># Create multiple MCP servers</span>
|
|
<span class="n">github_mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"GitHub API"</span><span class="p">)</span>
|
|
<span class="n">browser_mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Browser"</span><span class="p">)</span>
|
|
<span class="n">curl_mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Curl"</span><span class="p">)</span>
|
|
<span class="n">search_mcp</span> <span class="o">=</span> <span class="n">FastMCP</span><span class="p">(</span><span class="s2">"Search"</span><span class="p">)</span>
|
|
|
|
<span class="c1"># Method 1: Configure mount paths via settings (recommended for persistent configuration)</span>
|
|
<span class="n">github_mcp</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">mount_path</span> <span class="o">=</span> <span class="s2">"/github"</span>
|
|
<span class="n">browser_mcp</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">mount_path</span> <span class="o">=</span> <span class="s2">"/browser"</span>
|
|
|
|
<span class="c1"># Method 2: Pass mount path directly to sse_app (preferred for ad-hoc mounting)</span>
|
|
<span class="c1"># This approach doesn't modify the server's settings permanently</span>
|
|
|
|
<span class="c1"># Create Starlette app with multiple mounted servers</span>
|
|
<span class="n">app</span> <span class="o">=</span> <span class="n">Starlette</span><span class="p">(</span>
|
|
<span class="n">routes</span><span class="o">=</span><span class="p">[</span>
|
|
<span class="c1"># Using settings-based configuration</span>
|
|
<span class="n">Mount</span><span class="p">(</span><span class="s2">"/github"</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="n">github_mcp</span><span class="o">.</span><span class="n">sse_app</span><span class="p">()),</span>
|
|
<span class="n">Mount</span><span class="p">(</span><span class="s2">"/browser"</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="n">browser_mcp</span><span class="o">.</span><span class="n">sse_app</span><span class="p">()),</span>
|
|
<span class="c1"># Using direct mount path parameter</span>
|
|
<span class="n">Mount</span><span class="p">(</span><span class="s2">"/curl"</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="n">curl_mcp</span><span class="o">.</span><span class="n">sse_app</span><span class="p">(</span><span class="s2">"/curl"</span><span class="p">)),</span>
|
|
<span class="n">Mount</span><span class="p">(</span><span class="s2">"/search"</span><span class="p">,</span> <span class="n">app</span><span class="o">=</span><span class="n">search_mcp</span><span class="o">.</span><span class="n">sse_app</span><span class="p">(</span><span class="s2">"/search"</span><span class="p">)),</span>
|
|
<span class="p">]</span>
|
|
<span class="p">)</span>
|
|
|
|
<span class="c1"># Method 3: For direct execution, you can also pass the mount path to run()</span>
|
|
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
|
|
<span class="n">search_mcp</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">transport</span><span class="o">=</span><span class="s2">"sse"</span><span class="p">,</span> <span class="n">mount_path</span><span class="o">=</span><span class="s2">"/search"</span><span class="p">)</span>
|
|
</code></pre></div>
|
|
<p>For more information on mounting applications in Starlette, see the <a href="https://www.starlette.io/routing/#submounting-routes">Starlette documentation</a>.</p>
|
|
<h2 id="advanced-usage">Advanced Usage</h2>
|
|
<p>For the low-level server API, pagination, and direct handler registration, see <a href="../low-level-server/">Low-Level Server</a>.</p>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
</article>
|
|
</div>
|
|
|
|
|
|
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
|
|
|
|
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
|
|
</div>
|
|
|
|
</main>
|
|
|
|
<footer class="md-footer">
|
|
|
|
<div class="md-footer-meta md-typeset">
|
|
<div class="md-footer-meta__inner md-grid">
|
|
<div class="md-copyright">
|
|
|
|
|
|
Made with
|
|
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
|
|
Material for MkDocs
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
</div>
|
|
<div class="md-dialog" data-md-component="dialog">
|
|
<div class="md-dialog__inner md-typeset"></div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script id="__config" type="application/json">{"base": "..", "features": ["search.suggest", "search.highlight", "content.tabs.link", "content.code.annotate", "content.code.copy", "content.code.select", "navigation.path", "navigation.indexes", "navigation.sections", "navigation.tracking", "toc.follow"], "search": "../assets/javascripts/workers/search.973d3a69.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
|
|
|
|
|
|
<script src="../assets/javascripts/bundle.92b07e13.min.js"></script>
|
|
|
|
|
|
|
|
<script id="init-glightbox">const lightbox = GLightbox({"touchNavigation": true, "loop": false, "zoomable": true, "draggable": true, "openEffect": "zoom", "closeEffect": "zoom", "slideEffect": "slide"});
|
|
document$.subscribe(()=>{ lightbox.reload(); });
|
|
</script></body></html> |