Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions tools/gmail/oauth-draft/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ dependencies = [
# install it with `uv run --project ... --extra mcp oauth-draft-mcp`.
[project.optional-dependencies]
mcp = [
"mcp>=1.28.1",
"mcp>=2.0.0",
]

[project.scripts]
Expand Down Expand Up @@ -119,5 +119,5 @@ dev = [
"pytest>=9.1.1",
"ruff>=0.15.22",
# Needed to import and test `oauth_draft.mcp_server` (the `mcp` extra).
"mcp>=1.28.1",
"mcp>=2.0.0",
]
6 changes: 3 additions & 3 deletions tools/gmail/oauth-draft/src/oauth_draft/mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
from collections.abc import Iterator
from typing import Any

from mcp.server.fastmcp import FastMCP
from mcp.server.mcpserver import MCPServer

from oauth_draft import create_draft as _cd
from oauth_draft import setup_creds as _setup
Expand All @@ -81,7 +81,7 @@
refresh_access_token,
)

mcp = FastMCP("gmail-plaintext")
mcp = MCPServer("gmail-plaintext")


@contextlib.contextmanager
Expand All @@ -90,7 +90,7 @@ def _as_tool_error() -> Iterator[None]:

``create_draft.py`` / ``credentials.py`` raise ``SystemExit`` (they are
also console scripts). ``SystemExit`` is a ``BaseException``, not an
``Exception``, so without this it would propagate past FastMCP and kill
``Exception``, so without this it would propagate past MCPServer and kill
the server process instead of surfacing as a failed tool call.
"""
try:
Expand Down
4 changes: 2 additions & 2 deletions tools/gmail/oauth-draft/tests/test_mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,13 @@ def test_tools_are_registered_without_any_html_parameter():
names = {t.name for t in tools}
assert names == {"create_draft", "setup_credentials", "check_auth"}
by_name = {t.name: t for t in tools}
draft_props = by_name["create_draft"].inputSchema.get("properties", {})
draft_props = by_name["create_draft"].input_schema.get("properties", {})
# The draft tool must never expose an HTML / rich-text body knob.
assert not any("html" in p.lower() for p in draft_props)
assert {"to", "subject", "body"} <= set(draft_props)
# No tool anywhere exposes an html parameter.
for t in tools:
assert not any("html" in p.lower() for p in t.inputSchema.get("properties", {}))
assert not any("html" in p.lower() for p in t.input_schema.get("properties", {}))


def test_impl_produces_single_part_plain_text_with_verbatim_link():
Expand Down
111 changes: 57 additions & 54 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading