Repository: jlowin/fastmcp
Pull request #302 (2025-05-02 21:28:09)

Add method for retrieving current starlette request to FastMCP context
Easily access the current starlette request from context, as described in https://github.com/modelcontextprotocol/python-sdk/pull/380

Server:
```python
from fastmcp import Context, FastMCP

mcp = FastMCP()


@mcp.tool()
async def add_and_headers(a: int, b: int, ctx: Context) -> dict[str, Any]:
    request = ctx.get_starlette_request()
    return dict(result=a + b, headers=request.headers)


if __name__ == "__main__":
    mcp.run(transport="sse")
```
Client:
```python
import asyncio
from fastmcp import Client


async def main():
    async with Client("http://localhost:8000/sse") as client:
        result = await client.call_tool("add_and_headers", dict(a=1, b=2))
        print(result)


if __name__ == "__main__":
    asyncio.run(main())
```


Patch:
diff --git a/docs/clients/client.mdx b/docs/clients/client.mdx
index 5602887..21459df 100644
--- a/docs/clients/client.mdx
+++ b/docs/clients/client.mdx
@@ -149,34 +149,6 @@ The `Client` provides methods corresponding to standard MCP requests:
 *   **`list_prompts()`**: Retrieves available prompt templates.
 *   **`get_prompt(name: str, arguments: dict[str, Any] | None = None)`**: Retrieves a rendered prompt message list.
 
-### Raw MCP Protocol Objects
-
-The FastMCP client attempts to provide a "friendly" interface to the MCP protocol, but sometimes you may need access to the raw MCP protocol objects. Each of the main client methods that returns data has a corresponding `*_mcp` method that returns the raw MCP protocol objects directly.
-
-```python
-# Standard method - returns just the list of tools
-tools = await client.list_tools()
-# tools -> list[mcp.types.Tool]
-
-# Raw MCP method - returns the full protocol object
-result = await client.list_tools_mcp()
-# result -> mcp.types.ListToolsResult
-tools = result.tools
-```
-
-Available raw MCP methods:
-
-*   **`list_tools_mcp()`**: Returns `mcp.types.ListToolsResult`
-*   **`call_tool_mcp(name, arguments)`**: Returns `mcp.types.CallToolResult`
-*   **`list_resources_mcp()`**: Returns `mcp.types.ListResourcesResult`
-*   **`list_resource_templates_mcp()`**: Returns `mcp.types.ListResourceTemplatesResult`
-*   **`read_resource_mcp(uri)`**: Returns `mcp.types.ReadResourceResult`
-*   **`list_prompts_mcp()`**: Returns `mcp.types.ListPromptsResult`
-*   **`get_prompt_mcp(name, arguments)`**: Returns `mcp.types.GetPromptResult`
-*   **`complete_mcp(ref, argument)`**: Returns `mcp.types.CompleteResult`
-
-These methods are especially useful for debugging or when you need to access metadata or fields that aren't exposed by the simplified methods.
-
 ### Advanced Features
 
 MCP allows servers to interact with clients in order to provide additional capabilities. The `Client` constructor accepts additional configuration to handle these server requests.
@@ -296,5 +268,5 @@ async def safe_call_tool():
 Other errors, like connection failures, will raise standard Python exceptions (e.g., `ConnectionError`, `TimeoutError`). 
 
 <Tip>
-The client transport often has its own error-handling mechanisms, so you can not always trap errors like those raised by `call_tool` outside of the `async with` block. Instead, you can use `call_tool_mcp()` to get the raw `mcp.types.CallToolResult` object and handle errors yourself by checking its `isError` attribute.
+The client transport often has its own error-handling mechanisms, so you can not always trap errors like those raised by `call_tool` outside of the `async with` block. Instead, you can call `call_tool(..., _return_raw_result=True)` to get the raw `mcp.types.CallToolResult` object and handle errors yourself by checking its `isError` attribute.
 </Tip>
diff --git a/docs/servers/context.mdx b/docs/servers/context.mdx
index 2030451..e6554cb 100644
--- a/docs/servers/context.mdx
+++ b/docs/servers/context.mdx
@@ -269,11 +269,31 @@ async def advanced_tool(ctx: Context) -> str:
     return f"Server: {server_name}"
 ```
 
+For web applications, you can access the underlying HTTP request:
+
+```python
+@mcp.tool()
+async def handle_web_request(ctx: Context) -> dict:
+    """Access HTTP request information from the Starlette request."""
+    request = ctx.get_starlette_request()
+    
+    # Access HTTP headers, query parameters, etc.
+    user_agent = request.headers.get("user-agent", "Unknown")
+    client_ip = request.client.host if request.client else "Unknown"
+    
+    return {
+        "user_agent": user_agent,
+        "client_ip": client_ip,
+        "path": request.url.path,
+    }
+```
+
 **Advanced Properties:**
 
 - **`ctx.fastmcp -> FastMCP`**: Access the server instance the context belongs to
 - **`ctx.session`**: Access the raw `mcp.server.session.ServerSession` object
 - **`ctx.request_context`**: Access the raw `mcp.shared.context.RequestContext` object
+- **`ctx.get_starlette_request() -> Request`**: Access the active Starlette request object (when running with a web server)
 
 <Warning>
 Direct use of `session` or `request_context` requires understanding the low-level MCP Python SDK and may be less stable than using the methods provided directly on the `Context` object.
diff --git a/src/fastmcp/client/client.py b/src/fastmcp/client/client.py
index 7ca6528..d834ed7 100644
--- a/src/fastmcp/client/client.py
+++ b/src/fastmcp/client/client.py
@@ -1,7 +1,7 @@
 import datetime
 from contextlib import AbstractAsyncContextManager
 from pathlib import Path
-from typing import Any, cast
+from typing import Any, Literal, cast, overload
 
 import mcp.types
 from mcp import ClientSession
@@ -107,7 +107,6 @@ class Client:
             self._session = None
 
     # --- MCP Client Methods ---
-
     async def ping(self) -> None:
         """Send a ping request."""
         await self.session.send_ping()
@@ -129,100 +128,23 @@ class Client:
         """Send a roots/list_changed notification."""
         await self.session.send_roots_list_changed()
 
-    # --- Resources ---
-
-    async def list_resources_mcp(self) -> mcp.types.ListResourcesResult:
-        """Send a resources/list request and return the complete MCP protocol result.
-
-        Returns:
-            mcp.types.ListResourcesResult: The complete response object from the protocol,
-                containing the list of resources and any additional metadata.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.session.list_resources()
-        return result
-
     async def list_resources(self) -> list[mcp.types.Resource]:
-        """Retrieve a list of resources available on the server.
-
-        Returns:
-            list[mcp.types.Resource]: A list of Resource objects.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.list_resources_mcp()
+        """Send a resources/list request."""
+        result = await self.session.list_resources()
         return result.resources
 
-    async def list_resource_templates_mcp(
-        self,
-    ) -> mcp.types.ListResourceTemplatesResult:
-        """Send a resources/listResourceTemplates request and return the complete MCP protocol result.
-
-        Returns:
-            mcp.types.ListResourceTemplatesResult: The complete response object from the protocol,
-                containing the list of resource templates and any additional metadata.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
+    async def list_resource_templates(self) -> list[mcp.types.ResourceTemplate]:
+        """Send a resources/listResourceTemplates request."""
         result = await self.session.list_resource_templates()
-        return result
-
-    async def list_resource_templates(
-        self,
-    ) -> list[mcp.types.ResourceTemplate]:
-        """Retrieve a list of resource templates available on the server.
-
-        Returns:
-            list[mcp.types.ResourceTemplate]: A list of ResourceTemplate objects.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.list_resource_templates_mcp()
         return result.resourceTemplates
 
-    async def read_resource_mcp(
-        self, uri: AnyUrl | str
-    ) -> mcp.types.ReadResourceResult:
-        """Send a resources/read request and return the complete MCP protocol result.
-
-        Args:
-            uri (AnyUrl | str): The URI of the resource to read. Can be a string or an AnyUrl object.
-
-        Returns:
-            mcp.types.ReadResourceResult: The complete response object from the protocol,
-                containing the resource contents and any additional metadata.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        if isinstance(uri, str):
-            uri = AnyUrl(uri)  # Ensure AnyUrl
-        result = await self.session.read_resource(uri)
-        return result
-
     async def read_resource(
         self, uri: AnyUrl | str
     ) -> list[mcp.types.TextResourceContents | mcp.types.BlobResourceContents]:
-        """Read the contents of a resource or resolved template.
-
-        Args:
-            uri (AnyUrl | str): The URI of the resource to read. Can be a string or an AnyUrl object.
-
-        Returns:
-            list[mcp.types.TextResourceContents | mcp.types.BlobResourceContents]: A list of content
-                objects, typically containing either text or binary data.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
+        """Send a resources/read request."""
         if isinstance(uri, str):
             uri = AnyUrl(uri)  # Ensure AnyUrl
-        result = await self.read_resource_mcp(uri)
+        result = await self.session.read_resource(uri)
         return result.contents
 
     # async def subscribe_resource(self, uri: AnyUrl | str) -> None:
@@ -237,190 +159,66 @@ class Client:
     #         uri = AnyUrl(uri)
     #     await self.session.unsubscribe_resource(uri)
 
-    # --- Prompts ---
-
-    async def list_prompts_mcp(self) -> mcp.types.ListPromptsResult:
-        """Send a prompts/list request and return the complete MCP protocol result.
-
-        Returns:
-            mcp.types.ListPromptsResult: The complete response object from the protocol,
-                containing the list of prompts and any additional metadata.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.session.list_prompts()
-        return result
-
     async def list_prompts(self) -> list[mcp.types.Prompt]:
-        """Retrieve a list of prompts available on the server.
-
-        Returns:
-            list[mcp.types.Prompt]: A list of Prompt objects.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.list_prompts_mcp()
+        """Send a prompts/list request."""
+        result = await self.session.list_prompts()
         return result.prompts
 
-    # --- Prompt ---
-    async def get_prompt_mcp(
-        self, name: str, arguments: dict[str, str] | None = None
-    ) -> mcp.types.GetPromptResult:
-        """Send a prompts/get request and return the complete MCP protocol result.
-
-        Args:
-            name (str): The name of the prompt to retrieve.
-            arguments (dict[str, str] | None, optional): Arguments to pass to the prompt. Defaults to None.
-
-        Returns:
-            mcp.types.GetPromptResult: The complete response object from the protocol,
-                containing the prompt messages and any additional metadata.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.session.get_prompt(name=name, arguments=arguments)
-        return result
-
     async def get_prompt(
         self, name: str, arguments: dict[str, str] | None = None
     ) -> list[mcp.types.PromptMessage]:
-        """Retrieve a rendered prompt message list from the server.
-
-        Args:
-            name (str): The name of the prompt to retrieve.
-            arguments (dict[str, str] | None, optional): Arguments to pass to the prompt. Defaults to None.
-
-        Returns:
-            list[mcp.types.PromptMessage]: A list of prompt messages.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.get_prompt_mcp(name=name, arguments=arguments)
+        """Send a prompts/get request."""
+        result = await self.session.get_prompt(name, arguments)
         return result.messages
 
-    # --- Completion ---
-
-    async def complete_mcp(
-        self,
-        ref: mcp.types.ResourceReference | mcp.types.PromptReference,
-        argument: dict[str, str],
-    ) -> mcp.types.CompleteResult:
-        """Send a completion request and return the complete MCP protocol result.
-
-        Args:
-            ref (mcp.types.ResourceReference | mcp.types.PromptReference): The reference to complete.
-            argument (dict[str, str]): Arguments to pass to the completion request.
-
-        Returns:
-            mcp.types.CompleteResult: The complete response object from the protocol,
-                containing the completion and any additional metadata.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.session.complete(ref=ref, argument=argument)
-        return result
-
     async def complete(
         self,
         ref: mcp.types.ResourceReference | mcp.types.PromptReference,
         argument: dict[str, str],
     ) -> mcp.types.Completion:
-        """Send a completion request to the server.
-
-        Args:
-            ref (mcp.types.ResourceReference | mcp.types.PromptReference): The reference to complete.
-            argument (dict[str, str]): Arguments to pass to the completion request.
-
-        Returns:
-            mcp.types.Completion: The completion object.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.complete_mcp(ref=ref, argument=argument)
+        """Send a completion request."""
+        result = await self.session.complete(ref, argument)
         return result.completion
 
-    # --- Tools ---
-
-    async def list_tools_mcp(self) -> mcp.types.ListToolsResult:
-        """Send a tools/list request and return the complete MCP protocol result.
-
-        Returns:
-            mcp.types.ListToolsResult: The complete response object from the protocol,
-                containing the list of tools and any additional metadata.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.session.list_tools()
-        return result
-
     async def list_tools(self) -> list[mcp.types.Tool]:
-        """Retrieve a list of tools available on the server.
-
-        Returns:
-            list[mcp.types.Tool]: A list of Tool objects.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.list_tools_mcp()
+        """Send a tools/list request."""
+        result = await self.session.list_tools()
         return result.tools
 
-    # --- Call Tool ---
-
-    async def call_tool_mcp(
-        self, name: str, arguments: dict[str, Any]
-    ) -> mcp.types.CallToolResult:
-        """Send a tools/call request and return the complete MCP protocol result.
-
-        This method returns the raw CallToolResult object, which includes an isError flag
-        and other metadata. It does not raise an exception if the tool call results in an error.
-
-        Args:
-            name (str): The name of the tool to call.
-            arguments (dict[str, Any]): Arguments to pass to the tool.
-
-        Returns:
-            mcp.types.CallToolResult: The complete response object from the protocol,
-                containing the tool result and any additional metadata.
-
-        Raises:
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.session.call_tool(name=name, arguments=arguments)
-        return result
-
+    @overload
     async def call_tool(
         self,
         name: str,
         arguments: dict[str, Any] | None = None,
+        _return_raw_result: Literal[False] = False,
     ) -> list[
         mcp.types.TextContent | mcp.types.ImageContent | mcp.types.EmbeddedResource
-    ]:
-        """Call a tool on the server.
-
-        Unlike call_tool_mcp, this method raises a ClientError if the tool call results in an error.
+    ]: ...
 
-        Args:
-            name (str): The name of the tool to call.
-            arguments (dict[str, Any] | None, optional): Arguments to pass to the tool. Defaults to None.
-
-        Returns:
-            list[mcp.types.TextContent | mcp.types.ImageContent | mcp.types.EmbeddedResource]:
-                The content returned by the tool.
+    @overload
+    async def call_tool(
+        self,
+        name: str,
+        arguments: dict[str, Any] | None = None,
+        _return_raw_result: Literal[True] = True,
+    ) -> mcp.types.CallToolResult: ...
 
-        Raises:
-            ClientError: If the tool call results in an error.
-            RuntimeError: If called while the client is not connected.
-        """
-        result = await self.call_tool_mcp(name=name, arguments=arguments or {})
-        if result.isError:
+    async def call_tool(
+        self,
+        name: str,
+        arguments: dict[str, Any] | None = None,
+        _return_raw_result: bool = False,
+    ) -> (
+        list[
+            mcp.types.TextContent | mcp.types.ImageContent | mcp.types.EmbeddedResource
+        ]
+        | mcp.types.CallToolResult
+    ):
+        """Send a tools/call request."""
+        result = await self.session.call_tool(name, arguments)
+        if _return_raw_result:
+            return result
+        elif result.isError:
             msg = cast(mcp.types.TextContent, result.content[0]).text
             raise ClientError(msg)
         return result.content
diff --git a/src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py b/src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py
index 07e82e8..365dd95 100644
--- a/src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py
+++ b/src/fastmcp/contrib/bulk_tool_caller/bulk_tool_caller.py
@@ -123,7 +123,9 @@ class BulkToolCaller(MCPMixin):
         """
 
         async with Client(self.connection) as client:
-            result = await client.call_tool_mcp(name=tool, arguments=arguments)
+            result = await client.call_tool(
+                name=tool, arguments=arguments, _return_raw_result=True
+            )
 
             return CallToolRequestResult(
                 tool=tool,
diff --git a/src/fastmcp/server/context.py b/src/fastmcp/server/context.py
index ebb9126..34dd3ea 100644
--- a/src/fastmcp/server/context.py
+++ b/src/fastmcp/server/context.py
@@ -13,10 +13,12 @@ from mcp.types import (
     SamplingMessage,
     TextContent,
 )
-from pydantic import BaseModel
+from pydantic import BaseModel, ConfigDict
 from pydantic.networks import AnyUrl
+from starlette.requests import Request
 
 from fastmcp.server.server import FastMCP
+from fastmcp.utilities.http import get_current_starlette_request
 from fastmcp.utilities.logging import get_logger
 
 logger = get_logger(__name__)
@@ -59,6 +61,8 @@ class Context(BaseModel, Generic[ServerSessionT, LifespanContextT]):
     _request_context: RequestContext[ServerSessionT, LifespanContextT] | None
     _fastmcp: FastMCP | None
 
+    model_config = ConfigDict(arbitrary_types_allowed=True)
+
     def __init__(
         self,
         *,
@@ -222,3 +226,10 @@ class Context(BaseModel, Generic[ServerSessionT, LifespanContextT]):
         )
 
         return result.content
+
+    def get_starlette_request(self) -> Request:
+        """Get the active starlette request."""
+        request = get_current_starlette_request()
+        if request is None:
+            raise ValueError("Request is not available outside a Starlette request")
+        return request
diff --git a/src/fastmcp/server/proxy.py b/src/fastmcp/server/proxy.py
index ae0370a..ca16e52 100644
--- a/src/fastmcp/server/proxy.py
+++ b/src/fastmcp/server/proxy.py
@@ -65,9 +65,8 @@ class ProxyTool(Tool):
         # the client context manager will swallow any exceptions inside a TaskGroup
         # so we return the raw result and raise an exception ourselves
         async with self._client:
-            result = await self._client.call_tool_mcp(
-                name=self.name,
-                arguments=arguments,
+            result = await self._client.call_tool(
+                self.name, arguments, _return_raw_result=True
             )
         if result.isError:
             raise ValueError(cast(mcp.types.TextContent, result.content[0]).text)
diff --git a/src/fastmcp/server/server.py b/src/fastmcp/server/server.py
index dfb71c1..59cb6f0 100644
--- a/src/fastmcp/server/server.py
+++ b/src/fastmcp/server/server.py
@@ -59,6 +59,7 @@ from fastmcp.resources.template import ResourceTemplate
 from fastmcp.tools import ToolManager
 from fastmcp.tools.tool import Tool
 from fastmcp.utilities.decorators import DecoratedFunction
+from fastmcp.utilities.http import RequestMiddleware
 from fastmcp.utilities.logging import configure_logging, get_logger
 
 if TYPE_CHECKING:
@@ -822,10 +823,11 @@ class FastMCP(Generic[LifespanResultT]):
         log_level: str | None = None,
     ) -> None:
         """Run the server using SSE transport."""
-        starlette_app = self.sse_app()
+        app = self.sse_app()
+        app = RequestMiddleware(app)
 
         config = uvicorn.Config(
-            starlette_app,
+            app,
             host=host or self.settings.host,
             port=port or self.settings.port,
             log_level=log_level or self.settings.log_level.lower(),
diff --git a/src/fastmcp/utilities/http.py b/src/fastmcp/utilities/http.py
new file mode 100644
index 0000000..31f6d40
--- /dev/null
+++ b/src/fastmcp/utilities/http.py
@@ -0,0 +1,44 @@
+from __future__ import annotations
+
+from contextlib import (
+    asynccontextmanager,
+)
+from contextvars import ContextVar
+
+from starlette.requests import Request
+
+from fastmcp.utilities.logging import get_logger
+
+logger = get_logger(__name__)
+
+
+_current_starlette_request: ContextVar[Request | None] = ContextVar(
+    "starlette_request",
+    default=None,
+)
+
+
+@asynccontextmanager
+async def starlette_request_context(request: Request):
+    token = _current_starlette_request.set(request)
+    try:
+        yield
+    finally:
+        _current_starlette_request.reset(token)
+
+
+def get_current_starlette_request() -> Request | None:
+    return _current_starlette_request.get()
+
+
+class RequestMiddleware:
+    """
+    Middleware that stores each request in a ContextVar
+    """
+
+    def __init__(self, app):
+        self.app = app
+
+    async def __call__(self, scope, receive, send):
+        async with starlette_request_context(Request(scope)):
+            await self.app(scope, receive, send)


Test patch:
diff --git a/tests/client/test_client.py b/tests/client/test_client.py
index c6d671f..7bc0fe2 100644
--- a/tests/client/test_client.py
+++ b/tests/client/test_client.py
@@ -79,19 +79,6 @@ async def test_list_tools(fastmcp_server):
         assert set(tool.name for tool in result) == {"greet", "add"}
 
 
-async def test_list_tools_mcp(fastmcp_server):
-    """Test the list_tools_mcp method that returns raw MCP protocol objects."""
-    client = Client(transport=FastMCPTransport(fastmcp_server))
-
-    async with client:
-        result = await client.list_tools_mcp()
-
-        # Check that we got the raw MCP ListToolsResult object
-        assert hasattr(result, "tools")
-        assert len(result.tools) == 2
-        assert set(tool.name for tool in result.tools) == {"greet", "add"}
-
-
 async def test_call_tool(fastmcp_server):
     """Test calling a tool with InMemoryClient."""
     client = Client(transport=FastMCPTransport(fastmcp_server))
@@ -104,26 +91,6 @@ async def test_call_tool(fastmcp_server):
         assert "Hello, World!" in content_str
 
 
-async def test_call_tool_mcp(fastmcp_server):
-    """Test the call_tool_mcp method that returns raw MCP protocol objects."""
-    client = Client(transport=FastMCPTransport(fastmcp_server))
-
-    async with client:
-        result = await client.call_tool_mcp("greet", {"name": "World"})
-
-        # Check that we got the raw MCP CallToolResult object
-        assert hasattr(result, "content")
-        assert hasattr(result, "isError")
-        assert result.isError is False
-        # The content is a list, so we'll check the first element
-        # by properly accessing it
-        content = result.content
-        assert len(content) > 0
-        first_content = content[0]
-        content_str = str(first_content)
-        assert "Hello, World!" in content_str
-
-
 async def test_list_resources(fastmcp_server):
     """Test listing resources with InMemoryClient."""
     client = Client(transport=FastMCPTransport(fastmcp_server))
@@ -136,19 +103,6 @@ async def test_list_resources(fastmcp_server):
         assert str(result[0].uri) == "data://users"
 
 
-async def test_list_resources_mcp(fastmcp_server):
-    """Test the list_resources_mcp method that returns raw MCP protocol objects."""
-    client = Client(transport=FastMCPTransport(fastmcp_server))
-
-    async with client:
-        result = await client.list_resources_mcp()
-
-        # Check that we got the raw MCP ListResourcesResult object
-        assert hasattr(result, "resources")
-        assert len(result.resources) == 1
-        assert str(result.resources[0].uri) == "data://users"
-
-
 async def test_list_prompts(fastmcp_server):
     """Test listing prompts with InMemoryClient."""
     client = Client(transport=FastMCPTransport(fastmcp_server))
@@ -161,19 +115,6 @@ async def test_list_prompts(fastmcp_server):
         assert result[0].name == "welcome"
 
 
-async def test_list_prompts_mcp(fastmcp_server):
-    """Test the list_prompts_mcp method that returns raw MCP protocol objects."""
-    client = Client(transport=FastMCPTransport(fastmcp_server))
-
-    async with client:
-        result = await client.list_prompts_mcp()
-
-        # Check that we got the raw MCP ListPromptsResult object
-        assert hasattr(result, "prompts")
-        assert len(result.prompts) == 1
-        assert result.prompts[0].name == "welcome"
-
-
 async def test_get_prompt(fastmcp_server):
     """Test getting a prompt with InMemoryClient."""
     client = Client(transport=FastMCPTransport(fastmcp_server))
@@ -186,20 +127,6 @@ async def test_get_prompt(fastmcp_server):
         assert "Welcome to FastMCP, Developer!" in result_str
 
 
-async def test_get_prompt_mcp(fastmcp_server):
-    """Test the get_prompt_mcp method that returns raw MCP protocol objects."""
-    client = Client(transport=FastMCPTransport(fastmcp_server))
-
-    async with client:
-        result = await client.get_prompt_mcp("welcome", {"name": "Developer"})
-
-        # Check that we got the raw MCP GetPromptResult object
-        assert hasattr(result, "messages")
-        assert len(result.messages) > 0
-        result_str = str(result.messages)
-        assert "Welcome to FastMCP, Developer!" in result_str
-
-
 async def test_read_resource(fastmcp_server):
     """Test reading a resource with InMemoryClient."""
     client = Client(transport=FastMCPTransport(fastmcp_server))
@@ -218,26 +145,6 @@ async def test_read_resource(fastmcp_server):
         assert "Charlie" in contents_str
 
 
-async def test_read_resource_mcp(fastmcp_server):
-    """Test the read_resource_mcp method that returns raw MCP protocol objects."""
-    client = Client(transport=FastMCPTransport(fastmcp_server))
-
-    async with client:
-        # Use the URI from the resource we know exists in our server
-        uri = cast(
-            AnyUrl, "data://users"
-        )  # Use cast for type hint only, the URI is valid
-        result = await client.read_resource_mcp(uri)
-
-        # Check that we got the raw MCP ReadResourceResult object
-        assert hasattr(result, "contents")
-        assert len(result.contents) > 0
-        contents_str = str(result.contents[0])
-        assert "Alice" in contents_str
-        assert "Bob" in contents_str
-        assert "Charlie" in contents_str
-
-
 async def test_client_connection(fastmcp_server):
     """Test that the client connects and disconnects properly."""
     client = Client(transport=FastMCPTransport(fastmcp_server))
@@ -306,19 +213,6 @@ async def test_resource_template(fastmcp_server):
         assert '"active": true' in content_str
 
 
-async def test_list_resource_templates_mcp(fastmcp_server):
-    """Test the list_resource_templates_mcp method that returns raw MCP protocol objects."""
-    client = Client(transport=FastMCPTransport(fastmcp_server))
-
-    async with client:
-        result = await client.list_resource_templates_mcp()
-
-        # Check that we got the raw MCP ListResourceTemplatesResult object
-        assert hasattr(result, "resourceTemplates")
-        assert len(result.resourceTemplates) == 1
-        assert "data://user/{user_id}" in result.resourceTemplates[0].uriTemplate
-
-
 async def test_mcp_resource_generation(fastmcp_server):
     """Test that resources are properly generated in MCP format."""
     client = Client(transport=FastMCPTransport(fastmcp_server))
diff --git a/tests/server/test_server_interactions.py b/tests/server/test_server_interactions.py
index 9c7ed2b..98025f0 100644
--- a/tests/server/test_server_interactions.py
+++ b/tests/server/test_server_interactions.py
@@ -96,7 +96,7 @@ class TestTools:
 
     async def test_call_tool_error_as_client_raw(self, tool_server: FastMCP):
         async with Client(tool_server) as client:
-            result = await client.call_tool_mcp("error_tool", {})
+            result = await client.call_tool("error_tool", {}, _return_raw_result=True)
         assert result.isError
         assert isinstance(result.content[0], TextContent)
         assert "Test error" in result.content[0].text