chore: bump ruff (#1085)
This commit is contained in:
parent
6f43d1f170
commit
9301924f44
21 changed files with 56 additions and 57 deletions
|
|
@ -81,7 +81,7 @@ class CallbackHandler(BaseHTTPRequestHandler):
|
|||
<html>
|
||||
<body>
|
||||
<h1>Authorization Failed</h1>
|
||||
<p>Error: {query_params['error'][0]}</p>
|
||||
<p>Error: {query_params["error"][0]}</p>
|
||||
<p>You can close this window and return to the terminal.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import os
|
|||
from dataclasses import dataclass
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Annotated, Self
|
||||
from typing import Annotated, Self, TypeVar
|
||||
|
||||
import asyncpg
|
||||
import numpy as np
|
||||
|
|
@ -35,6 +35,8 @@ REINFORCEMENT_FACTOR = 1.1
|
|||
DEFAULT_LLM_MODEL = "openai:gpt-4o"
|
||||
DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small"
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
mcp = FastMCP(
|
||||
"memory",
|
||||
dependencies=[
|
||||
|
|
@ -57,7 +59,7 @@ def cosine_similarity(a: list[float], b: list[float]) -> float:
|
|||
return np.dot(a_array, b_array) / (np.linalg.norm(a_array) * np.linalg.norm(b_array))
|
||||
|
||||
|
||||
async def do_ai[T](
|
||||
async def do_ai(
|
||||
user_prompt: str,
|
||||
system_prompt: str,
|
||||
result_type: type[T] | Annotated,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from mcp.server.fastmcp import FastMCP
|
|||
mcp = FastMCP()
|
||||
|
||||
|
||||
@mcp.tool(description="🌟 A tool that uses various Unicode characters in its description: " "á é í ó ú ñ 漢字 🎉")
|
||||
@mcp.tool(description="🌟 A tool that uses various Unicode characters in its description: á é í ó ú ñ 漢字 🎉")
|
||||
def hello_unicode(name: str = "世界", greeting: str = "¡Hola") -> str:
|
||||
"""
|
||||
A simple tool that demonstrates Unicode handling in:
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ class SimpleOAuthProvider(OAuthAuthorizationServerProvider):
|
|||
}
|
||||
|
||||
# Build simple login URL that points to login page
|
||||
auth_url = f"{self.auth_callback_url}" f"?state={state}" f"&client_id={client.client_id}"
|
||||
auth_url = f"{self.auth_callback_url}?state={state}&client_id={client.client_id}"
|
||||
|
||||
return auth_url
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ class SimpleOAuthProvider(OAuthAuthorizationServerProvider):
|
|||
<p><strong>Username:</strong> demo_user<br>
|
||||
<strong>Password:</strong> demo_password</p>
|
||||
|
||||
<form action="{self.server_url.rstrip('/')}/login/callback" method="post">
|
||||
<form action="{self.server_url.rstrip("/")}/login/callback" method="post">
|
||||
<input type="hidden" name="state" value="{state}">
|
||||
<div class="form-group">
|
||||
<label>Username:</label>
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ def main(
|
|||
for i in range(count):
|
||||
await ctx.session.send_log_message(
|
||||
level="info",
|
||||
data=f"Notification {i+1}/{count} from caller: {caller}",
|
||||
data=f"Notification {i + 1}/{count} from caller: {caller}",
|
||||
logger="notification_stream",
|
||||
related_request_id=ctx.request_id,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ def main(
|
|||
for i in range(count):
|
||||
# Include more detailed message for resumability demonstration
|
||||
notification_msg = (
|
||||
f"[{i+1}/{count}] Event from '{caller}' - "
|
||||
f"[{i + 1}/{count}] Event from '{caller}' - "
|
||||
f"Use Last-Event-ID to resume if disconnected"
|
||||
)
|
||||
await ctx.session.send_log_message(
|
||||
|
|
@ -69,7 +69,7 @@ def main(
|
|||
# - nowhere (if GET request isn't supported)
|
||||
related_request_id=ctx.request_id,
|
||||
)
|
||||
logger.debug(f"Sent notification {i+1}/{count} for caller: {caller}")
|
||||
logger.debug(f"Sent notification {i + 1}/{count} for caller: {caller}")
|
||||
if i < count - 1: # Don't wait after the last notification
|
||||
await anyio.sleep(interval)
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ def get_uv_path() -> str:
|
|||
uv_path = shutil.which("uv")
|
||||
if not uv_path:
|
||||
logger.error(
|
||||
"uv executable not found in PATH, falling back to 'uv'. " "Please ensure uv is installed and in your PATH"
|
||||
"uv executable not found in PATH, falling back to 'uv'. Please ensure uv is installed and in your PATH"
|
||||
)
|
||||
return "uv" # Fall back to just "uv" if not found
|
||||
return uv_path
|
||||
|
|
|
|||
|
|
@ -150,10 +150,10 @@ def _import_server(file: Path, server_object: str | None = None):
|
|||
True if it's supported.
|
||||
"""
|
||||
if not isinstance(server_object, FastMCP):
|
||||
logger.error(f"The server object {object_name} is of type " f"{type(server_object)} (expecting {FastMCP}).")
|
||||
logger.error(f"The server object {object_name} is of type {type(server_object)} (expecting {FastMCP}).")
|
||||
if isinstance(server_object, LowLevelServer):
|
||||
logger.warning(
|
||||
"Note that only FastMCP server is supported. Low level " "Server class is not yet supported."
|
||||
"Note that only FastMCP server is supported. Low level Server class is not yet supported."
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
|
@ -164,7 +164,7 @@ def _import_server(file: Path, server_object: str | None = None):
|
|||
for name in ["mcp", "server", "app"]:
|
||||
if hasattr(module, name):
|
||||
if not _check_server_object(getattr(module, name), f"{file}:{name}"):
|
||||
logger.error(f"Ignoring object '{file}:{name}' as it's not a valid " "server object")
|
||||
logger.error(f"Ignoring object '{file}:{name}' as it's not a valid server object")
|
||||
continue
|
||||
return getattr(module, name)
|
||||
|
||||
|
|
@ -269,7 +269,7 @@ def dev(
|
|||
npx_cmd = _get_npx_command()
|
||||
if not npx_cmd:
|
||||
logger.error(
|
||||
"npx not found. Please ensure Node.js and npm are properly installed " "and added to your system PATH."
|
||||
"npx not found. Please ensure Node.js and npm are properly installed and added to your system PATH."
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
|
@ -371,7 +371,7 @@ def install(
|
|||
typer.Option(
|
||||
"--name",
|
||||
"-n",
|
||||
help="Custom name for the server (defaults to server's name attribute or" " file name)",
|
||||
help="Custom name for the server (defaults to server's name attribute or file name)",
|
||||
),
|
||||
] = None,
|
||||
with_editable: Annotated[
|
||||
|
|
@ -445,7 +445,7 @@ def install(
|
|||
name = server.name
|
||||
except (ImportError, ModuleNotFoundError) as e:
|
||||
logger.debug(
|
||||
"Could not import server (likely missing dependencies), using file" " name",
|
||||
"Could not import server (likely missing dependencies), using file name",
|
||||
extra={"error": str(e)},
|
||||
)
|
||||
name = file.stem
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ class ClientSession(
|
|||
)
|
||||
|
||||
if result.protocolVersion not in SUPPORTED_PROTOCOL_VERSIONS:
|
||||
raise RuntimeError("Unsupported protocol version from the server: " f"{result.protocolVersion}")
|
||||
raise RuntimeError(f"Unsupported protocol version from the server: {result.protocolVersion}")
|
||||
|
||||
await self.send_notification(
|
||||
types.ClientNotification(types.InitializedNotification(method="notifications/initialized"))
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ async def sse_client(
|
|||
or url_parsed.scheme != endpoint_parsed.scheme
|
||||
):
|
||||
error_msg = (
|
||||
"Endpoint origin does not match " f"connection origin: {endpoint_url}"
|
||||
f"Endpoint origin does not match connection origin: {endpoint_url}"
|
||||
)
|
||||
logger.error(error_msg)
|
||||
raise ValueError(error_msg)
|
||||
|
|
@ -125,7 +125,7 @@ async def sse_client(
|
|||
),
|
||||
)
|
||||
response.raise_for_status()
|
||||
logger.debug("Client message sent successfully: " f"{response.status_code}")
|
||||
logger.debug(f"Client message sent successfully: {response.status_code}")
|
||||
except Exception as exc:
|
||||
logger.error(f"Error in post_writer: {exc}")
|
||||
finally:
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class AuthorizationRequest(BaseModel):
|
|||
state: str | None = Field(None, description="Optional state parameter")
|
||||
scope: str | None = Field(
|
||||
None,
|
||||
description="Optional scope; if specified, should be " "a space-separated list of scope strings",
|
||||
description="Optional scope; if specified, should be a space-separated list of scope strings",
|
||||
)
|
||||
resource: str | None = Field(
|
||||
None,
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class RegistrationHandler:
|
|||
return PydanticJSONResponse(
|
||||
content=RegistrationErrorResponse(
|
||||
error="invalid_client_metadata",
|
||||
error_description="grant_types must be authorization_code " "and refresh_token",
|
||||
error_description="grant_types must be authorization_code and refresh_token",
|
||||
),
|
||||
status_code=400,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -119,9 +119,7 @@ class TokenHandler:
|
|||
return self.response(
|
||||
TokenErrorResponse(
|
||||
error="unsupported_grant_type",
|
||||
error_description=(
|
||||
f"Unsupported grant type (supported grant types are " f"{client_info.grant_types})"
|
||||
),
|
||||
error_description=(f"Unsupported grant type (supported grant types are {client_info.grant_types})"),
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -166,7 +164,7 @@ class TokenHandler:
|
|||
return self.response(
|
||||
TokenErrorResponse(
|
||||
error="invalid_request",
|
||||
error_description=("redirect_uri did not match the one " "used when creating auth code"),
|
||||
error_description=("redirect_uri did not match the one used when creating auth code"),
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -222,7 +220,7 @@ class TokenHandler:
|
|||
return self.response(
|
||||
TokenErrorResponse(
|
||||
error="invalid_scope",
|
||||
error_description=(f"cannot request scope `{scope}` " "not provided by refresh token"),
|
||||
error_description=(f"cannot request scope `{scope}` not provided by refresh token"),
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -390,7 +390,7 @@ class FastMCP:
|
|||
# Check if user passed function directly instead of calling decorator
|
||||
if callable(name):
|
||||
raise TypeError(
|
||||
"The @tool decorator was used incorrectly. " "Did you forget to call it? Use @tool() instead of @tool"
|
||||
"The @tool decorator was used incorrectly. Did you forget to call it? Use @tool() instead of @tool"
|
||||
)
|
||||
|
||||
def decorator(fn: AnyFunction) -> AnyFunction:
|
||||
|
|
@ -497,7 +497,7 @@ class FastMCP:
|
|||
|
||||
if uri_params != func_params:
|
||||
raise ValueError(
|
||||
f"Mismatch between URI parameters {uri_params} " f"and function parameters {func_params}"
|
||||
f"Mismatch between URI parameters {uri_params} and function parameters {func_params}"
|
||||
)
|
||||
|
||||
# Register as template
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class Tool(BaseModel):
|
|||
description: str = Field(description="Description of what the tool does")
|
||||
parameters: dict[str, Any] = Field(description="JSON schema for tool parameters")
|
||||
fn_metadata: FuncMetadata = Field(
|
||||
description="Metadata about the function including a pydantic model for tool" " arguments"
|
||||
description="Metadata about the function including a pydantic model for tool arguments"
|
||||
)
|
||||
is_async: bool = Field(description="Whether the tool is async")
|
||||
context_kwarg: str | None = Field(None, description="Name of the kwarg that should receive context")
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ class OAuthClientMetadata(BaseModel):
|
|||
elif len(self.redirect_uris) == 1:
|
||||
return self.redirect_uris[0]
|
||||
else:
|
||||
raise InvalidRedirectUriError("redirect_uri must be specified when client " "has multiple registered URIs")
|
||||
raise InvalidRedirectUriError("redirect_uri must be specified when client has multiple registered URIs")
|
||||
|
||||
|
||||
class OAuthClientInformationFull(OAuthClientMetadata):
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ class BaseSession(
|
|||
except Exception as e:
|
||||
# For other validation errors, log and continue
|
||||
logging.warning(
|
||||
f"Failed to validate notification: {e}. " f"Message was: {message.message.root}"
|
||||
f"Failed to validate notification: {e}. Message was: {message.message.root}"
|
||||
)
|
||||
else: # Response or error
|
||||
stream = self._response_streams.pop(message.message.root.id, None)
|
||||
|
|
@ -410,7 +410,7 @@ class BaseSession(
|
|||
await stream.send(message.message.root)
|
||||
else:
|
||||
await self._handle_incoming(
|
||||
RuntimeError("Received response with an unknown " f"request ID: {message}")
|
||||
RuntimeError(f"Received response with an unknown request ID: {message}")
|
||||
)
|
||||
|
||||
except anyio.ClosedResourceError:
|
||||
|
|
|
|||
|
|
@ -57,8 +57,7 @@ async def test_send_request_stream_cleanup():
|
|||
|
||||
# Verify that no response streams were leaked
|
||||
assert len(session._response_streams) == initial_stream_count, (
|
||||
f"Expected {initial_stream_count} response streams after request, "
|
||||
f"but found {len(session._response_streams)}"
|
||||
f"Expected {initial_stream_count} response streams after request, but found {len(session._response_streams)}"
|
||||
)
|
||||
|
||||
# Clean up
|
||||
|
|
|
|||
|
|
@ -658,7 +658,7 @@ class TestAuthEndpoints:
|
|||
assert "error" in error_data
|
||||
assert error_data["error"] == "invalid_client_metadata"
|
||||
assert error_data["error_description"] == (
|
||||
"redirect_uris.0: Input should be a valid URL, " "relative URL without a base"
|
||||
"redirect_uris.0: Input should be a valid URL, relative URL without a base"
|
||||
)
|
||||
|
||||
@pytest.mark.anyio
|
||||
|
|
|
|||
|
|
@ -696,7 +696,7 @@ def everything_streamable_http_server(
|
|||
time.sleep(0.1)
|
||||
attempt += 1
|
||||
else:
|
||||
raise RuntimeError(f"Comprehensive StreamableHTTP server failed to start after " f"{max_attempts} attempts")
|
||||
raise RuntimeError(f"Comprehensive StreamableHTTP server failed to start after {max_attempts} attempts")
|
||||
|
||||
yield
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue