11from datetime import timedelta
2- from typing import Any , Protocol
2+ from typing import Annotated , Any , Protocol
33
44import anyio .lowlevel
55from anyio .streams .memory import MemoryObjectReceiveStream , MemoryObjectSendStream
6- from pydantic import AnyUrl , TypeAdapter
6+ from pydantic import TypeAdapter
7+ from pydantic .networks import AnyUrl , UrlConstraints
78
89import mcp .types as types
910from mcp .shared .context import RequestContext
1011from mcp .shared .message import SessionMessage
11- from mcp .shared .session import BaseSession , ProgressFnT , RequestResponder
12+ from mcp .shared .session import (
13+ BaseSession ,
14+ ProgressFnT ,
15+ RequestResponder ,
16+ ResourceProgressFnT ,
17+ )
1218from mcp .shared .version import SUPPORTED_PROTOCOL_VERSIONS
1319
1420DEFAULT_CLIENT_INFO = types .Implementation (name = "mcp" , version = "0.1.0" )
@@ -179,6 +185,9 @@ async def send_progress_notification(
179185 progress : float ,
180186 total : float | None = None ,
181187 message : str | None = None ,
188+ # TODO check whether MCP spec allows clients to create resources
189+ # for server and therefore whether resource notifications
190+ # would be required here too
182191 ) -> None :
183192 """Send a progress notification."""
184193 await self .send_notification (
@@ -208,7 +217,10 @@ async def set_logging_level(self, level: types.LoggingLevel) -> types.EmptyResul
208217 )
209218
210219 async def list_resources (
211- self , cursor : str | None = None
220+ self ,
221+ cursor : str | None = None ,
222+ # TODO suggest in progress resources should be excluded by default?
223+ # possibly add an optional flag to include?
212224 ) -> types .ListResourcesResult :
213225 """Send a resources/list request."""
214226 return await self .send_request (
@@ -239,7 +251,9 @@ async def list_resource_templates(
239251 types .ListResourceTemplatesResult ,
240252 )
241253
242- async def read_resource (self , uri : AnyUrl ) -> types .ReadResourceResult :
254+ async def read_resource (
255+ self , uri : Annotated [AnyUrl , UrlConstraints (host_required = False )]
256+ ) -> types .ReadResourceResult :
243257 """Send a resources/read request."""
244258 return await self .send_request (
245259 types .ClientRequest (
@@ -251,7 +265,9 @@ async def read_resource(self, uri: AnyUrl) -> types.ReadResourceResult:
251265 types .ReadResourceResult ,
252266 )
253267
254- async def subscribe_resource (self , uri : AnyUrl ) -> types .EmptyResult :
268+ async def subscribe_resource (
269+ self , uri : Annotated [AnyUrl , UrlConstraints (host_required = False )]
270+ ) -> types .EmptyResult :
255271 """Send a resources/subscribe request."""
256272 return await self .send_request (
257273 types .ClientRequest (
@@ -263,7 +279,9 @@ async def subscribe_resource(self, uri: AnyUrl) -> types.EmptyResult:
263279 types .EmptyResult ,
264280 )
265281
266- async def unsubscribe_resource (self , uri : AnyUrl ) -> types .EmptyResult :
282+ async def unsubscribe_resource (
283+ self , uri : Annotated [AnyUrl , UrlConstraints (host_required = False )]
284+ ) -> types .EmptyResult :
267285 """Send a resources/unsubscribe request."""
268286 return await self .send_request (
269287 types .ClientRequest (
@@ -280,7 +298,7 @@ async def call_tool(
280298 name : str ,
281299 arguments : dict [str , Any ] | None = None ,
282300 read_timeout_seconds : timedelta | None = None ,
283- progress_callback : ProgressFnT | None = None ,
301+ progress_callback : ProgressFnT | ResourceProgressFnT | None = None ,
284302 ) -> types .CallToolResult :
285303 """Send a tools/call request with optional progress callback support."""
286304
0 commit comments