Skip to content
Merged
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
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ dependencies = [

[project.optional-dependencies]
mcp = [
"mcp>=1.0,<2.0",
"mcp>=2.0,<3.0",
]
benchmark = [
"sentence-transformers>=3.0",
Expand Down
10 changes: 6 additions & 4 deletions src/semble/mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
from pathlib import Path
from typing import Annotated, Literal

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

from semble.cache import get_validated_cache, save_index_to_cache
from semble.index import SembleIndex
from semble.index.dense import load_model
from semble.types import ContentType
from semble.utils import format_results, is_git_url, resolve_chunk
from semble.version import __version__

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -68,10 +69,11 @@ def _resolve_content_selection(
return (ContentType(content),)


def create_server(cache: _IndexCache, default_content: Sequence[ContentType] = (ContentType.CODE,)) -> FastMCP:
"""Build and return a configured FastMCP server backed by the given cache."""
server = FastMCP(
def create_server(cache: _IndexCache, default_content: Sequence[ContentType] = (ContentType.CODE,)) -> MCPServer:
"""Build and return a configured MCP server backed by the given cache."""
server = MCPServer(
"semble",
version=__version__,
instructions=(
"Instant code search for any local or remote git repository. "
"Call `search` once with a focused query, it returns the file path and exact line. "
Expand Down
2 changes: 1 addition & 1 deletion tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def test_cli_entrypoint_works_without_mcp_installed(
monkeypatch.setattr(sys, "argv", argv)
monkeypatch.setitem(sys.modules, "mcp", None)
monkeypatch.setitem(sys.modules, "mcp.server", None)
monkeypatch.setitem(sys.modules, "mcp.server.fastmcp", None)
monkeypatch.setitem(sys.modules, "mcp.server.mcpserver", None)
monkeypatch.setitem(sys.modules, "semble.mcp", None)
with patch("semble.cli.SembleIndex.from_path", return_value=fake_index):
if expect_system_exit:
Expand Down
8 changes: 4 additions & 4 deletions tests/test_mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@


def _tool_text(result: Any) -> str:
"""Extract the text string from a FastMCP call_tool result."""
return result[0][0].text
"""Extract the text string from an MCP call_tool result."""
return result.content[0].text


async def _call_tool(
Expand Down Expand Up @@ -430,7 +430,7 @@ async def fake_stdio() -> None:
)
with (
patch("semble.mcp.load_model", **load_kwargs),
patch("mcp.server.fastmcp.FastMCP.run_stdio_async", side_effect=fake_stdio) as mock_run,
patch("mcp.server.mcpserver.MCPServer.run_stdio_async", side_effect=fake_stdio) as mock_run,
):
await serve()

Expand All @@ -452,7 +452,7 @@ async def fake_run_stdio() -> None:

with (
patch("semble.mcp.load_model", side_effect=blocking_load_model),
patch("mcp.server.fastmcp.FastMCP.run_stdio_async", side_effect=fake_run_stdio),
patch("mcp.server.mcpserver.MCPServer.run_stdio_async", side_effect=fake_run_stdio),
):
await serve()

Expand Down
71 changes: 32 additions & 39 deletions uv.lock

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

Loading