refactor: move inline imports to module level (#1893)

This commit is contained in:
Max Isbey 2026-01-16 15:54:08 +01:00 • committed by GitHub
commit 5d80f4efc8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 58 additions and 122 deletions

View file

@ -1,6 +1,7 @@
import argparse import argparse
import logging import logging
import sys import sys
import warnings
from functools import partial from functools import partial
from urllib.parse import urlparse from urllib.parse import urlparse
@ -15,8 +16,6 @@ from mcp.shared.message import SessionMessage
from mcp.shared.session import RequestResponder from mcp.shared.session import RequestResponder
if not sys.warnoptions: if not sys.warnoptions:
import warnings
warnings.simplefilter("ignore") warnings.simplefilter("ignore")
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)

View file

@ -9,6 +9,7 @@ Provides OAuth providers for machine-to-machine authentication flows:
""" """
import time import time
import warnings
from collections.abc import Awaitable, Callable from collections.abc import Awaitable, Callable
from typing import Any, Literal from typing import Any, Literal
from uuid import uuid4 from uuid import uuid4
@ -409,8 +410,6 @@ class RFC7523OAuthClientProvider(OAuthClientProvider):
timeout: float = 300.0, timeout: float = 300.0,
jwt_parameters: JWTParameters | None = None, jwt_parameters: JWTParameters | None = None,
) -> None: ) -> None:
import warnings
warnings.warn( warnings.warn(
"RFC7523OAuthClientProvider is deprecated. Use ClientCredentialsOAuthProvider " "RFC7523OAuthClientProvider is deprecated. Use ClientCredentialsOAuthProvider "
"or PrivateKeyJWTOAuthProvider instead.", "or PrivateKeyJWTOAuthProvider instead.",

View file

@ -1,6 +1,7 @@
import importlib.metadata import importlib.metadata
import logging import logging
import sys import sys
import warnings
import anyio import anyio
@ -10,8 +11,6 @@ from mcp.server.stdio import stdio_server
from mcp.types import ServerCapabilities from mcp.types import ServerCapabilities
if not sys.warnoptions: if not sys.warnoptions:
import warnings
warnings.simplefilter("ignore") warnings.simplefilter("ignore")
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)

View file

@ -74,6 +74,7 @@ import logging
import warnings import warnings
from collections.abc import AsyncIterator, Awaitable, Callable, Iterable from collections.abc import AsyncIterator, Awaitable, Callable, Iterable
from contextlib import AbstractAsyncContextManager, AsyncExitStack, asynccontextmanager from contextlib import AbstractAsyncContextManager, AsyncExitStack, asynccontextmanager
from importlib.metadata import version as importlib_version
from typing import Any, Generic, TypeAlias, cast from typing import Any, Generic, TypeAlias, cast
import anyio import anyio
@ -173,9 +174,7 @@ class Server(Generic[LifespanResultT, RequestT]):
def pkg_version(package: str) -> str: def pkg_version(package: str) -> str:
try: try:
from importlib.metadata import version return importlib_version(package)
return version(package)
except Exception: # pragma: no cover except Exception: # pragma: no cover
pass pass

View file

@ -1,4 +1,5 @@
import urllib.parse import urllib.parse
import warnings
import jwt import jwt
import pytest import pytest
@ -60,8 +61,6 @@ def rfc7523_oauth_provider(client_metadata: OAuthClientMetadata, mock_storage: M
"""Mock callback handler.""" """Mock callback handler."""
return "test_auth_code", "test_state" return "test_auth_code", "test_state"
import warnings
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning) warnings.simplefilter("ignore", DeprecationWarning)
return RFC7523OAuthClientProvider( return RFC7523OAuthClientProvider(

View file

@ -5,7 +5,7 @@ Tests for refactored OAuth client authentication implementation.
import base64 import base64
import time import time
from unittest import mock from unittest import mock
from urllib.parse import unquote from urllib.parse import parse_qs, quote, unquote, urlparse
import httpx import httpx
import pytest import pytest
@ -27,6 +27,8 @@ from mcp.client.auth.utils import (
is_valid_client_metadata_url, is_valid_client_metadata_url,
should_use_client_metadata_url, should_use_client_metadata_url,
) )
from mcp.server.auth.routes import build_metadata
from mcp.server.auth.settings import ClientRegistrationOptions, RevocationOptions
from mcp.shared.auth import ( from mcp.shared.auth import (
OAuthClientInformationFull, OAuthClientInformationFull,
OAuthClientMetadata, OAuthClientMetadata,
@ -758,8 +760,6 @@ class TestProtectedResourceMetadata:
content = request.content.decode() content = request.content.decode()
assert "resource=" in content assert "resource=" in content
# Check URL-encoded resource parameter # Check URL-encoded resource parameter
from urllib.parse import quote
expected_resource = quote(oauth_provider.context.get_resource_url(), safe="") expected_resource = quote(oauth_provider.context.get_resource_url(), safe="")
assert f"resource={expected_resource}" in content assert f"resource={expected_resource}" in content
@ -1226,8 +1226,6 @@ class TestAuthFlow:
"%3A", ":" "%3A", ":"
).replace("+", " ") ).replace("+", " ")
# Extract state from redirect URL # Extract state from redirect URL
from urllib.parse import parse_qs, urlparse
parsed = urlparse(url) parsed = urlparse(url)
params = parse_qs(parsed.query) params = parse_qs(parsed.query)
captured_state = params.get("state", [None])[0] captured_state = params.get("state", [None])[0]
@ -1336,9 +1334,6 @@ def test_build_metadata(
registration_endpoint: str, registration_endpoint: str,
revocation_endpoint: str, revocation_endpoint: str,
): ):
from mcp.server.auth.routes import build_metadata
from mcp.server.auth.settings import ClientRegistrationOptions, RevocationOptions
metadata = build_metadata( metadata = build_metadata(
issuer_url=AnyHttpUrl(issuer_url), issuer_url=AnyHttpUrl(issuer_url),
service_documentation_url=AnyHttpUrl(service_documentation_url), service_documentation_url=AnyHttpUrl(service_documentation_url),

View file

@ -7,12 +7,20 @@ Verifies that Unicode text is correctly transmitted and received in both directi
import multiprocessing import multiprocessing
import socket import socket
from collections.abc import Generator from collections.abc import AsyncGenerator, Generator
from contextlib import asynccontextmanager
from typing import Any
import pytest import pytest
from starlette.applications import Starlette
from starlette.routing import Mount
import mcp.types as types
from mcp.client.session import ClientSession from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamable_http_client from mcp.client.streamable_http import streamable_http_client
from mcp.server import Server
from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
from mcp.types import TextContent, Tool
from tests.test_helpers import wait_for_server from tests.test_helpers import wait_for_server
# Test constants with various Unicode characters # Test constants with various Unicode characters
@ -37,19 +45,7 @@ UNICODE_TEST_STRINGS = {
def run_unicode_server(port: int) -> None: # pragma: no cover def run_unicode_server(port: int) -> None: # pragma: no cover
"""Run the Unicode test server in a separate process.""" """Run the Unicode test server in a separate process."""
# Import inside the function since this runs in a separate process
from collections.abc import AsyncGenerator
from contextlib import asynccontextmanager
from typing import Any
import uvicorn import uvicorn
from starlette.applications import Starlette
from starlette.routing import Mount
import mcp.types as types
from mcp.server import Server
from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
from mcp.types import TextContent, Tool
# Need to recreate the server setup in this process # Need to recreate the server setup in this process
server = Server(name="unicode_test_server") server = Server(name="unicode_test_server")

View file

@ -2,6 +2,7 @@ import pytest
from pydantic import FileUrl from pydantic import FileUrl
from mcp.client.session import ClientSession from mcp.client.session import ClientSession
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.server import Context from mcp.server.fastmcp.server import Context
from mcp.server.session import ServerSession from mcp.server.session import ServerSession
from mcp.shared.context import RequestContext from mcp.shared.context import RequestContext
@ -13,8 +14,6 @@ from mcp.types import ListRootsResult, Root, TextContent
@pytest.mark.anyio @pytest.mark.anyio
async def test_list_roots_callback(): async def test_list_roots_callback():
from mcp.server.fastmcp import FastMCP
server = FastMCP("test") server = FastMCP("test")
callback_return = ListRootsResult( callback_return = ListRootsResult(

View file

@ -3,6 +3,7 @@ from typing import Any, Literal
import pytest import pytest
import mcp.types as types import mcp.types as types
from mcp.server.fastmcp import FastMCP
from mcp.shared.memory import ( from mcp.shared.memory import (
create_connected_server_and_client_session as create_session, create_connected_server_and_client_session as create_session,
) )
@ -23,8 +24,6 @@ class LoggingCollector:
@pytest.mark.anyio @pytest.mark.anyio
async def test_logging_callback(): async def test_logging_callback():
from mcp.server.fastmcp import FastMCP
server = FastMCP("test") server = FastMCP("test")
logging_collector = LoggingCollector() logging_collector = LoggingCollector()

View file

@ -1,8 +1,10 @@
import inspect
import logging import logging
from contextlib import contextmanager from contextlib import contextmanager
from typing import Any from typing import Any
from unittest.mock import patch from unittest.mock import patch
import jsonschema
import pytest import pytest
from mcp.server.lowlevel import Server from mcp.server.lowlevel import Server
@ -19,15 +21,11 @@ def bypass_server_output_validation():
This simulates a malicious or non-compliant server that doesn't validate This simulates a malicious or non-compliant server that doesn't validate
its outputs, allowing us to test client-side validation. its outputs, allowing us to test client-side validation.
""" """
import jsonschema
# Save the original validate function # Save the original validate function
original_validate = jsonschema.validate original_validate = jsonschema.validate
# Create a mock that tracks which module is calling it # Create a mock that tracks which module is calling it
def selective_mock(instance: Any = None, schema: Any = None, *args: Any, **kwargs: Any) -> None: def selective_mock(instance: Any = None, schema: Any = None, *args: Any, **kwargs: Any) -> None:
import inspect
# Check the call stack to see where this is being called from # Check the call stack to see where this is being called from
for frame_info in inspect.stack(): for frame_info in inspect.stack():
# If called from the server module, skip validation # If called from the server module, skip validation

View file

@ -1,6 +1,7 @@
import pytest import pytest
from mcp.client.session import ClientSession from mcp.client.session import ClientSession
from mcp.server.fastmcp import FastMCP
from mcp.shared.context import RequestContext from mcp.shared.context import RequestContext
from mcp.shared.memory import ( from mcp.shared.memory import (
create_connected_server_and_client_session as create_session, create_connected_server_and_client_session as create_session,
@ -17,8 +18,6 @@ from mcp.types import (
@pytest.mark.anyio @pytest.mark.anyio
async def test_sampling_callback(): async def test_sampling_callback():
from mcp.server.fastmcp import FastMCP
server = FastMCP("test") server = FastMCP("test")
callback_return = CreateMessageResult( callback_return = CreateMessageResult(
@ -63,8 +62,6 @@ async def test_sampling_callback():
@pytest.mark.anyio @pytest.mark.anyio
async def test_create_message_backwards_compat_single_content(): async def test_create_message_backwards_compat_single_content():
"""Test backwards compatibility: create_message without tools returns single content.""" """Test backwards compatibility: create_message without tools returns single content."""
from mcp.server.fastmcp import FastMCP
server = FastMCP("test") server = FastMCP("test")
# Callback returns single content (text) # Callback returns single content (text)

View file

@ -1,6 +1,7 @@
import contextlib import contextlib
from unittest import mock from unittest import mock
import httpx
import pytest import pytest
import mcp import mcp
@ -356,8 +357,6 @@ class TestClientSessionGroup:
assert isinstance(server_params_instance, StreamableHttpParameters) assert isinstance(server_params_instance, StreamableHttpParameters)
# Verify streamable_http_client was called with url, httpx_client, and terminate_on_close # Verify streamable_http_client was called with url, httpx_client, and terminate_on_close
# The http_client is created by the real create_mcp_http_client # The http_client is created by the real create_mcp_http_client
import httpx
call_args = mock_specific_client_func.call_args call_args = mock_specific_client_func.call_args
assert call_args.kwargs["url"] == server_params_instance.url assert call_args.kwargs["url"] == server_params_instance.url
assert call_args.kwargs["terminate_on_close"] == server_params_instance.terminate_on_close assert call_args.kwargs["terminate_on_close"] == server_params_instance.terminate_on_close

View file

@ -10,7 +10,12 @@ import anyio
import pytest import pytest
from mcp.client.session import ClientSession from mcp.client.session import ClientSession
from mcp.client.stdio import StdioServerParameters, _create_platform_compatible_process, stdio_client from mcp.client.stdio import (
StdioServerParameters,
_create_platform_compatible_process,
_terminate_process_tree,
stdio_client,
)
from mcp.shared.exceptions import McpError from mcp.shared.exceptions import McpError
from mcp.shared.message import SessionMessage from mcp.shared.message import SessionMessage
from mcp.types import CONNECTION_CLOSED, JSONRPCMessage, JSONRPCRequest, JSONRPCResponse from mcp.types import CONNECTION_CLOSED, JSONRPCMessage, JSONRPCRequest, JSONRPCResponse
@ -312,8 +317,6 @@ class TestChildProcessCleanup:
# Terminate using our function # Terminate using our function
print("Terminating process and children...") print("Terminating process and children...")
from mcp.client.stdio import _terminate_process_tree
await _terminate_process_tree(proc) await _terminate_process_tree(proc)
# Verify processes stopped # Verify processes stopped
@ -413,8 +416,6 @@ class TestChildProcessCleanup:
assert new_size > initial_size, f"{name} process should be writing" assert new_size > initial_size, f"{name} process should be writing"
# Terminate the whole tree # Terminate the whole tree
from mcp.client.stdio import _terminate_process_tree
await _terminate_process_tree(proc) await _terminate_process_tree(proc)
# Verify all stopped # Verify all stopped
@ -494,8 +495,6 @@ class TestChildProcessCleanup:
assert size2 > size1, "Child should be writing" assert size2 > size1, "Child should be writing"
# Terminate - this will kill the process group even if parent exits first # Terminate - this will kill the process group even if parent exits first
from mcp.client.stdio import _terminate_process_tree
await _terminate_process_tree(proc) await _terminate_process_tree(proc)
# Verify child stopped # Verify child stopped

View file

@ -2,6 +2,9 @@
Tests for OAuth error handling in the auth handlers. Tests for OAuth error handling in the auth handlers.
""" """
import base64
import hashlib
import secrets
import unittest.mock import unittest.mock
from typing import Any from typing import Any
from urllib.parse import parse_qs, urlparse from urllib.parse import parse_qs, urlparse
@ -14,6 +17,7 @@ from starlette.applications import Starlette
from mcp.server.auth.provider import AuthorizeError, RegistrationError, TokenError from mcp.server.auth.provider import AuthorizeError, RegistrationError, TokenError
from mcp.server.auth.routes import create_auth_routes from mcp.server.auth.routes import create_auth_routes
from mcp.server.auth.settings import ClientRegistrationOptions, RevocationOptions
from tests.server.fastmcp.auth.test_auth_integration import MockOAuthProvider from tests.server.fastmcp.auth.test_auth_integration import MockOAuthProvider
@ -25,8 +29,6 @@ def oauth_provider():
@pytest.fixture @pytest.fixture
def app(oauth_provider: MockOAuthProvider): def app(oauth_provider: MockOAuthProvider):
from mcp.server.auth.settings import ClientRegistrationOptions, RevocationOptions
# Enable client registration # Enable client registration
client_registration_options = ClientRegistrationOptions(enabled=True) client_registration_options = ClientRegistrationOptions(enabled=True)
revocation_options = RevocationOptions(enabled=True) revocation_options = RevocationOptions(enabled=True)
@ -53,10 +55,6 @@ def client(app: Starlette):
@pytest.fixture @pytest.fixture
def pkce_challenge(): def pkce_challenge():
"""Create a PKCE challenge with code_verifier and code_challenge.""" """Create a PKCE challenge with code_verifier and code_challenge."""
import base64
import hashlib
import secrets
# Generate a code verifier # Generate a code verifier
code_verifier = secrets.token_urlsafe(64)[:128] code_verifier = secrets.token_urlsafe(64)[:128]

View file

@ -2,6 +2,8 @@
Integration tests for MCP Oauth Protected Resource. Integration tests for MCP Oauth Protected Resource.
""" """
from urllib.parse import urlparse
import httpx import httpx
import pytest import pytest
from inline_snapshot import snapshot from inline_snapshot import snapshot
@ -159,8 +161,6 @@ class TestRouteConsistency:
) )
# Extract path from metadata URL # Extract path from metadata URL
from urllib.parse import urlparse
metadata_path = urlparse(str(metadata_url)).path metadata_path = urlparse(str(metadata_url)).path
# Verify consistency # Verify consistency
@ -181,8 +181,6 @@ class TestRouteConsistency:
# Test URL generation # Test URL generation
metadata_url = build_resource_metadata_url(resource_url_obj) metadata_url = build_resource_metadata_url(resource_url_obj)
from urllib.parse import urlparse
url_path = urlparse(str(metadata_url)).path url_path = urlparse(str(metadata_url)).path
# Test route creation # Test route creation

View file

@ -1258,8 +1258,6 @@ class TestAuthEndpoints:
) )
# Send base64 without colon (invalid format) # Send base64 without colon (invalid format)
import base64
invalid_creds = base64.b64encode(b"no-colon-here").decode() invalid_creds = base64.b64encode(b"no-colon-here").decode()
response = await test_client.post( response = await test_client.post(
"/token", "/token",
@ -1306,8 +1304,6 @@ class TestAuthEndpoints:
) )
# Send different client_id in Basic auth header # Send different client_id in Basic auth header
import base64
wrong_creds = base64.b64encode(f"wrong-client-id:{client_info['client_secret']}".encode()).decode() wrong_creds = base64.b64encode(f"wrong-client-id:{client_info['client_secret']}".encode()).decode()
response = await test_client.post( response = await test_client.post(
"/token", "/token",

View file

@ -5,13 +5,14 @@
# pyright: reportUnknownLambdaType=false # pyright: reportUnknownLambdaType=false
from collections.abc import Callable from collections.abc import Callable
from dataclasses import dataclass from dataclasses import dataclass
from typing import Annotated, Any, Final, TypedDict from typing import Annotated, Any, Final, NamedTuple, TypedDict
import annotated_types import annotated_types
import pytest import pytest
from dirty_equals import IsPartialDict from dirty_equals import IsPartialDict
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from mcp.server.fastmcp.exceptions import InvalidSignature
from mcp.server.fastmcp.utilities.func_metadata import func_metadata from mcp.server.fastmcp.utilities.func_metadata import func_metadata
from mcp.types import CallToolResult from mcp.types import CallToolResult
@ -558,7 +559,6 @@ async def test_str_annotation_runtime_validation():
def test_structured_output_requires_return_annotation(): def test_structured_output_requires_return_annotation():
"""Test that structured_output=True requires a return annotation""" """Test that structured_output=True requires a return annotation"""
from mcp.server.fastmcp.exceptions import InvalidSignature
def func_no_annotation(): # pragma: no cover def func_no_annotation(): # pragma: no cover
return "hello" return "hello"
@ -881,8 +881,6 @@ def test_tool_call_result_annotated_is_structured_and_invalid():
def test_tool_call_result_in_optional_is_rejected(): def test_tool_call_result_in_optional_is_rejected():
"""Test that Optional[CallToolResult] raises InvalidSignature""" """Test that Optional[CallToolResult] raises InvalidSignature"""
from mcp.server.fastmcp.exceptions import InvalidSignature
def func_optional_call_tool_result() -> CallToolResult | None: # pragma: no cover def func_optional_call_tool_result() -> CallToolResult | None: # pragma: no cover
return CallToolResult(content=[]) return CallToolResult(content=[])
@ -896,8 +894,6 @@ def test_tool_call_result_in_optional_is_rejected():
def test_tool_call_result_in_union_is_rejected(): def test_tool_call_result_in_union_is_rejected():
"""Test that Union[str, CallToolResult] raises InvalidSignature""" """Test that Union[str, CallToolResult] raises InvalidSignature"""
from mcp.server.fastmcp.exceptions import InvalidSignature
def func_union_call_tool_result() -> str | CallToolResult: # pragma: no cover def func_union_call_tool_result() -> str | CallToolResult: # pragma: no cover
return CallToolResult(content=[]) return CallToolResult(content=[])
@ -910,7 +906,6 @@ def test_tool_call_result_in_union_is_rejected():
def test_tool_call_result_in_pipe_union_is_rejected(): def test_tool_call_result_in_pipe_union_is_rejected():
"""Test that str | CallToolResult raises InvalidSignature""" """Test that str | CallToolResult raises InvalidSignature"""
from mcp.server.fastmcp.exceptions import InvalidSignature
def func_pipe_union_call_tool_result() -> str | CallToolResult: # pragma: no cover def func_pipe_union_call_tool_result() -> str | CallToolResult: # pragma: no cover
return CallToolResult(content=[]) return CallToolResult(content=[])
@ -985,9 +980,6 @@ def test_structured_output_nested_models():
def test_structured_output_unserializable_type_error(): def test_structured_output_unserializable_type_error():
"""Test error when structured_output=True is used with unserializable types""" """Test error when structured_output=True is used with unserializable types"""
from typing import NamedTuple
from mcp.server.fastmcp.exceptions import InvalidSignature
# Test with a class that has non-serializable default values # Test with a class that has non-serializable default values
class ConfigWithCallable: class ConfigWithCallable:
@ -1185,8 +1177,6 @@ def test_basemodel_reserved_names_with_json_preparsing():
def test_disallowed_type_qualifier(): def test_disallowed_type_qualifier():
from mcp.server.fastmcp.exceptions import InvalidSignature
def func_disallowed_qualifier() -> Final[int]: # type: ignore def func_disallowed_qualifier() -> Final[int]: # type: ignore
pass # pragma: no cover pass # pragma: no cover

View file

@ -51,8 +51,10 @@ from mcp.types import (
NotificationParams, NotificationParams,
ProgressNotification, ProgressNotification,
ProgressNotificationParams, ProgressNotificationParams,
PromptReference,
ReadResourceResult, ReadResourceResult,
ResourceListChangedNotification, ResourceListChangedNotification,
ResourceTemplateReference,
ServerNotification, ServerNotification,
ServerRequest, ServerRequest,
TextContent, TextContent,
@ -583,8 +585,6 @@ async def test_completion(server_transport: str, server_url: str) -> None:
assert result.capabilities.prompts is not None assert result.capabilities.prompts is not None
# Test resource completion # Test resource completion
from mcp.types import ResourceTemplateReference
completion_result = await session.complete( completion_result = await session.complete(
ref=ResourceTemplateReference(type="ref/resource", uri="github://repos/{owner}/{repo}"), ref=ResourceTemplateReference(type="ref/resource", uri="github://repos/{owner}/{repo}"),
argument={"name": "repo", "value": ""}, argument={"name": "repo", "value": ""},
@ -600,8 +600,6 @@ async def test_completion(server_transport: str, server_url: str) -> None:
assert "specification" in completion_result.completion.values assert "specification" in completion_result.completion.values
# Test prompt completion # Test prompt completion
from mcp.types import PromptReference
completion_result = await session.complete( completion_result = await session.complete(
ref=PromptReference(type="ref/prompt", name="review_code"), ref=PromptReference(type="ref/prompt", name="review_code"),
argument={"name": "language", "value": "py"}, argument={"name": "language", "value": "py"},
@ -644,8 +642,6 @@ async def test_fastmcp_quickstart(server_transport: str, server_url: str) -> Non
assert tool_result.content[0].text == "30" assert tool_result.content[0].text == "30"
# Test greeting resource directly # Test greeting resource directly
from pydantic import AnyUrl
resource_result = await session.read_resource(AnyUrl("greeting://Alice")) resource_result = await session.read_resource(AnyUrl("greeting://Alice"))
assert len(resource_result.contents) == 1 assert len(resource_result.contents) == 1
assert isinstance(resource_result.contents[0], TextResourceContents) assert isinstance(resource_result.contents[0], TextResourceContents)

View file

@ -5,9 +5,11 @@ from unittest.mock import patch
import pytest import pytest
from pydantic import BaseModel from pydantic import BaseModel
from starlette.applications import Starlette
from starlette.routing import Mount, Route from starlette.routing import Mount, Route
from mcp.server.fastmcp import Context, FastMCP from mcp.server.fastmcp import Context, FastMCP
from mcp.server.fastmcp.exceptions import ToolError
from mcp.server.fastmcp.prompts.base import Message, UserMessage from mcp.server.fastmcp.prompts.base import Message, UserMessage
from mcp.server.fastmcp.resources import FileResource, FunctionResource from mcp.server.fastmcp.resources import FileResource, FunctionResource
from mcp.server.fastmcp.utilities.types import Audio, Image from mcp.server.fastmcp.utilities.types import Audio, Image
@ -51,8 +53,6 @@ class TestServer:
@pytest.mark.anyio @pytest.mark.anyio
async def test_sse_app_returns_starlette_app(self): async def test_sse_app_returns_starlette_app(self):
"""Test that sse_app returns a Starlette application with correct routes.""" """Test that sse_app returns a Starlette application with correct routes."""
from starlette.applications import Starlette
mcp = FastMCP("test", host="0.0.0.0") # Use 0.0.0.0 to avoid auto DNS protection mcp = FastMCP("test", host="0.0.0.0") # Use 0.0.0.0 to avoid auto DNS protection
app = mcp.sse_app() app = mcp.sse_app()
@ -617,8 +617,6 @@ class TestServerTools:
@pytest.mark.anyio @pytest.mark.anyio
async def test_remove_nonexistent_tool(self): async def test_remove_nonexistent_tool(self):
"""Test that removing a non-existent tool raises ToolError.""" """Test that removing a non-existent tool raises ToolError."""
from mcp.server.fastmcp.exceptions import ToolError
mcp = FastMCP() mcp = FastMCP()
with pytest.raises(ToolError, match="Unknown tool: nonexistent"): with pytest.raises(ToolError, match="Unknown tool: nonexistent"):

View file

@ -2,10 +2,11 @@
import anyio import anyio
import pytest import pytest
from pydantic import BaseModel, Field
from mcp import types from mcp import types
from mcp.client.session import ClientSession from mcp.client.session import ClientSession
from mcp.server.elicitation import CancelledElicitation, DeclinedElicitation from mcp.server.elicitation import CancelledElicitation, DeclinedElicitation, elicit_url
from mcp.server.fastmcp import Context, FastMCP from mcp.server.fastmcp import Context, FastMCP
from mcp.server.session import ServerSession from mcp.server.session import ServerSession
from mcp.shared.context import RequestContext from mcp.shared.context import RequestContext
@ -110,8 +111,6 @@ async def test_url_elicitation_cancel():
@pytest.mark.anyio @pytest.mark.anyio
async def test_url_elicitation_helper_function(): async def test_url_elicitation_helper_function():
"""Test the elicit_url helper function.""" """Test the elicit_url helper function."""
from mcp.server.elicitation import elicit_url
mcp = FastMCP(name="URLElicitationHelperServer") mcp = FastMCP(name="URLElicitationHelperServer")
@mcp.tool(description="Tool using elicit_url helper") @mcp.tool(description="Tool using elicit_url helper")
@ -180,8 +179,6 @@ async def test_url_no_content_in_response():
@pytest.mark.anyio @pytest.mark.anyio
async def test_form_mode_still_works(): async def test_form_mode_still_works():
"""Ensure form mode elicitation still works after SEP 1036.""" """Ensure form mode elicitation still works after SEP 1036."""
from pydantic import BaseModel, Field
mcp = FastMCP(name="FormModeBackwardCompatServer") mcp = FastMCP(name="FormModeBackwardCompatServer")
class NameSchema(BaseModel): class NameSchema(BaseModel):
@ -267,8 +264,6 @@ async def test_url_elicitation_required_error_code():
@pytest.mark.anyio @pytest.mark.anyio
async def test_elicit_url_typed_results(): async def test_elicit_url_typed_results():
"""Test that elicit_url returns properly typed result objects.""" """Test that elicit_url returns properly typed result objects."""
from mcp.server.elicitation import elicit_url
mcp = FastMCP(name="TypedResultsServer") mcp = FastMCP(name="TypedResultsServer")
@mcp.tool(description="Test declined result") @mcp.tool(description="Test declined result")
@ -329,8 +324,6 @@ async def test_elicit_url_typed_results():
@pytest.mark.anyio @pytest.mark.anyio
async def test_deprecated_elicit_method(): async def test_deprecated_elicit_method():
"""Test the deprecated elicit() method for backward compatibility.""" """Test the deprecated elicit() method for backward compatibility."""
from pydantic import BaseModel, Field
mcp = FastMCP(name="DeprecatedElicitServer") mcp = FastMCP(name="DeprecatedElicitServer")
class EmailSchema(BaseModel): class EmailSchema(BaseModel):

Some files were not shown because too many files have changed in this diff Show more