Skip to content

[BUG] MCP server fails with FastMCP 2.8.1 - unexpected keyword argument 'log_level' #164

Closed

Description

@potatopotaro

Description

The MCP server fails to start with FastMCP 2.8.1 due to passing 'log_level' parameter that is not supported.

Error

TypeError: FastMCP.run_stdio_async() got an unexpected keyword argument 'log_level'

Environment

  • Basic Memory: 0.13.8.dev1
  • FastMCP: 2.8.1
  • Python: 3.13.5
  • Installation method: uv tool

Root Cause

Commit 7be001c added 'log_level' parameter to fix deprecation warnings, but this is incompatible with FastMCP 2.8.1.

Workaround

None currently available in dev version.

Activity

  1. potatopotaro commented on Jun 21, 2025

    @potatopotaro
    Author

    Oops, my Claude code made this on its own, so sorry. Still debugging.

  2. groksrc commented on Jun 23, 2025

    @groksrc
    Member

    This is likely fixed in #150 and will be available in the next release.

  3. added this to the v0.14.0 milestone on Jun 24, 2025
  4. adamdrzewiecki commented on Jun 25, 2025

    @adamdrzewiecki

    I don't think it's the same.
    I built the server from the main repo, but when I try to run it with the stdio transport, it throws:

    2025-06-25 16:50:44.815 | /usr/local/lib/python3.12/site-packages/sqlalchemy/sql/schema.py:3624: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
    2025-06-25 16:50:44.815 |   return util.wrap_callable(lambda ctx: fn(), fn)  # type: ignore
    2025-06-25 16:50:45.110 | ╭───────────────────── Traceback (most recent call last) ──────────────────────╮
    2025-06-25 16:50:45.110 | │ /usr/local/lib/python3.12/site-packages/basic_memory/cli/commands/mcp.py:79  │
    2025-06-25 16:50:45.110 | │ in mcp                                                                       │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │   76 │   logger.info(f"Starting MCP server with {transport.upper()} transpor │
    2025-06-25 16:50:45.110 | │   77 │                                                                       │
    2025-06-25 16:50:45.110 | │   78 │   if transport == "stdio":                                            │
    2025-06-25 16:50:45.110 | │ ❱ 79 │   │   mcp_server.run(                                                 │
    2025-06-25 16:50:45.110 | │   80 │   │   │   transport=transport,                                        │
    2025-06-25 16:50:45.110 | │   81 │   │   │   log_level="INFO",                                           │
    2025-06-25 16:50:45.110 | │   82 │   │   )                                                               │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
    2025-06-25 16:50:45.110 | │ │   app_config = BasicMemoryConfig(                                        │ │
    2025-06-25 16:50:45.110 | │ │                │   env='dev',                                            │ │
    2025-06-25 16:50:45.110 | │ │                │   projects={'main': '/root/basic-memory'},              │ │
    2025-06-25 16:50:45.110 | │ │                │   default_project='main',                               │ │
    2025-06-25 16:50:45.110 | │ │                │   log_level='INFO',                                     │ │
    2025-06-25 16:50:45.110 | │ │                │   sync_delay=1000,                                      │ │
    2025-06-25 16:50:45.110 | │ │                │   update_permalinks_on_move=False,                      │ │
    2025-06-25 16:50:45.110 | │ │                │   sync_changes=True                                     │ │
    2025-06-25 16:50:45.110 | │ │                )                                                         │ │
    2025-06-25 16:50:45.110 | │ │ auth_enabled = False                                                     │ │
    2025-06-25 16:50:45.110 | │ │         host = '0.0.0.0'                                                 │ │
    2025-06-25 16:50:45.110 | │ │           os = <module 'os' (frozen)>                                    │ │
    2025-06-25 16:50:45.110 | │ │         path = '/mcp'                                                    │ │
    2025-06-25 16:50:45.110 | │ │         port = 8000                                                      │ │
    2025-06-25 16:50:45.110 | │ │  sync_thread = <Thread(Thread-2 (run_file_sync), started daemon          │ │
    2025-06-25 16:50:45.110 | │ │                281473540223360)>                                         │ │
    2025-06-25 16:50:45.110 | │ │    threading = <module 'threading' from                                  │ │
    2025-06-25 16:50:45.110 | │ │                '/usr/local/lib/python3.12/threading.py'>                 │ │
    2025-06-25 16:50:45.110 | │ │    transport = 'stdio'                                                   │ │
    2025-06-25 16:50:45.110 | │ ╰──────────────────────────────────────────────────────────────────────────╯ │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ /usr/local/lib/python3.12/site-packages/fastmcp/server/server.py:315 in run  │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │    312 │   │   │   transport: Transport protocol to use ("stdio", "sse", or  │
    2025-06-25 16:50:45.110 | │    313 │   │   """                                                           │
    2025-06-25 16:50:45.110 | │    314 │   │                                                                 │
    2025-06-25 16:50:45.110 | │ ❱  315 │   │   anyio.run(partial(self.run_async, transport, **transport_kwar │
    2025-06-25 16:50:45.110 | │    316 │                                                                     │
    2025-06-25 16:50:45.110 | │    317 │   def _setup_handlers(self) -> None:                                │
    2025-06-25 16:50:45.110 | │    318 │   │   """Set up core MCP protocol handlers."""                      │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ ╭────────────────── locals ──────────────────╮                               │
    2025-06-25 16:50:45.110 | │ │             self = FastMCP('Basic Memory') │                               │
    2025-06-25 16:50:45.110 | │ │        transport = 'stdio'                 │                               │
    2025-06-25 16:50:45.110 | │ │ transport_kwargs = {'log_level': 'INFO'}   │                               │
    2025-06-25 16:50:45.110 | │ ╰────────────────────────────────────────────╯                               │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ /usr/local/lib/python3.12/site-packages/anyio/_core/_eventloop.py:74 in run  │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │    71 │                                                                      │
    2025-06-25 16:50:45.110 | │    72 │   try:                                                               │
    2025-06-25 16:50:45.110 | │    73 │   │   backend_options = backend_options or {}                        │
    2025-06-25 16:50:45.110 | │ ❱  74 │   │   return async_backend.run(func, args, {}, backend_options)      │
    2025-06-25 16:50:45.110 | │    75 │   finally:                                                           │
    2025-06-25 16:50:45.110 | │    76 │   │   if token:                                                      │
    2025-06-25 16:50:45.110 | │    77 │   │   │   sniffio.current_async_library_cvar.reset(token)            │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
    2025-06-25 16:50:45.110 | │ │            args = ()                                                     │ │
    2025-06-25 16:50:45.110 | │ │         backend = 'asyncio'                                              │ │
    2025-06-25 16:50:45.110 | │ │ backend_options = {}                                                     │ │
    2025-06-25 16:50:45.110 | │ │            func = functools.partial(<bound method FastMCP.run_async of   │ │
    2025-06-25 16:50:45.110 | │ │                   FastMCP('Basic Memory')>, 'stdio', log_level='INFO')   │ │
    2025-06-25 16:50:45.110 | │ │           token = <Token used var=<ContextVar                            │ │
    2025-06-25 16:50:45.110 | │ │                   name='current_async_library_cvar' default=None at      │ │
    2025-06-25 16:50:45.110 | │ │                   0xffffb3c9a250> at 0xffffabcd1bc0>                     │ │
    2025-06-25 16:50:45.110 | │ ╰──────────────────────────────────────────────────────────────────────────╯ │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ /usr/local/lib/python3.12/site-packages/anyio/_backends/_asyncio.py:2310 in  │
    2025-06-25 16:50:45.110 | │ run                                                                          │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │   2307 │   │   │   loop_factory = uvloop.new_event_loop                      │
    2025-06-25 16:50:45.110 | │   2308 │   │                                                                 │
    2025-06-25 16:50:45.110 | │   2309 │   │   with Runner(debug=debug, loop_factory=loop_factory) as runner │
    2025-06-25 16:50:45.110 | │ ❱ 2310 │   │   │   return runner.run(wrapper())                              │
    2025-06-25 16:50:45.110 | │   2311 │                                                                     │
    2025-06-25 16:50:45.110 | │   2312 │   @classmethod                                                      │
    2025-06-25 16:50:45.110 | │   2313 │   def current_token(cls) -> object:                                 │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
    2025-06-25 16:50:45.110 | │ │         args = ()                                                        │ │
    2025-06-25 16:50:45.110 | │ │        debug = None                                                      │ │
    2025-06-25 16:50:45.110 | │ │         func = functools.partial(<bound method FastMCP.run_async of      │ │
    2025-06-25 16:50:45.110 | │ │                FastMCP('Basic Memory')>, 'stdio', log_level='INFO')      │ │
    2025-06-25 16:50:45.110 | │ │       kwargs = {}                                                        │ │
    2025-06-25 16:50:45.110 | │ │ loop_factory = None                                                      │ │
    2025-06-25 16:50:45.110 | │ │      options = {}                                                        │ │
    2025-06-25 16:50:45.110 | │ │       runner = <asyncio.runners.Runner object at 0xffffabdb8aa0>         │ │
    2025-06-25 16:50:45.110 | │ ╰──────────────────────────────────────────────────────────────────────────╯ │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ /usr/local/lib/python3.12/asyncio/runners.py:118 in run                      │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │   115 │   │                                                                  │
    2025-06-25 16:50:45.110 | │   116 │   │   self._interrupt_count = 0                                      │
    2025-06-25 16:50:45.110 | │   117 │   │   try:                                                           │
    2025-06-25 16:50:45.110 | │ ❱ 118 │   │   │   return self._loop.run_until_complete(task)                 │
    2025-06-25 16:50:45.110 | │   119 │   │   except exceptions.CancelledError:                              │
    2025-06-25 16:50:45.110 | │   120 │   │   │   if self._interrupt_count > 0:                              │
    2025-06-25 16:50:45.110 | │   121 │   │   │   │   uncancel = getattr(task, "uncancel", None)             │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
    2025-06-25 16:50:45.110 | │ │        context = <_contextvars.Context object at 0xffffabe74ec0>         │ │
    2025-06-25 16:50:45.110 | │ │           coro = <coroutine object AsyncIOBackend.run.<locals>.wrapper   │ │
    2025-06-25 16:50:45.110 | │ │                  at 0xffffaba21a80>                                      │ │
    2025-06-25 16:50:45.110 | │ │           self = <asyncio.runners.Runner object at 0xffffabdb8aa0>       │ │
    2025-06-25 16:50:45.110 | │ │ sigint_handler = functools.partial(<bound method Runner._on_sigint of    │ │
    2025-06-25 16:50:45.110 | │ │                  <asyncio.runners.Runner object at 0xffffabdb8aa0>>,     │ │
    2025-06-25 16:50:45.110 | │ │                  main_task=<Task finished name='functools'               │ │
    2025-06-25 16:50:45.110 | │ │                  coro=<AsyncIOBackend.run.<locals>.wrapper() done,       │ │
    2025-06-25 16:50:45.110 | │ │                  defined at                                              │ │
    2025-06-25 16:50:45.110 | │ │                  /usr/local/lib/python3.12/site-packages/anyio/_backend… │ │
    2025-06-25 16:50:45.110 | │ │                  exception=TypeError("FastMCP.run_stdio_async() got an   │ │
    2025-06-25 16:50:45.110 | │ │                  unexpected keyword argument 'log_level'")>)             │ │
    2025-06-25 16:50:45.110 | │ │           task = <Task finished name='functools'                         │ │
    2025-06-25 16:50:45.110 | │ │                  coro=<AsyncIOBackend.run.<locals>.wrapper() done,       │ │
    2025-06-25 16:50:45.110 | │ │                  defined at                                              │ │
    2025-06-25 16:50:45.110 | │ │                  /usr/local/lib/python3.12/site-packages/anyio/_backend… │ │
    2025-06-25 16:50:45.110 | │ │                  exception=TypeError("FastMCP.run_stdio_async() got an   │ │
    2025-06-25 16:50:45.110 | │ │                  unexpected keyword argument 'log_level'")>              │ │
    2025-06-25 16:50:45.110 | │ ╰──────────────────────────────────────────────────────────────────────────╯ │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ /usr/local/lib/python3.12/asyncio/base_events.py:691 in run_until_complete   │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │    688 │   │   if not future.done():                                         │
    2025-06-25 16:50:45.110 | │    689 │   │   │   raise RuntimeError('Event loop stopped before Future comp │
    2025-06-25 16:50:45.110 | │    690 │   │                                                                 │
    2025-06-25 16:50:45.110 | │ ❱  691 │   │   return future.result()                                        │
    2025-06-25 16:50:45.110 | │    692 │                                                                     │
    2025-06-25 16:50:45.110 | │    693 │   def stop(self):                                                   │
    2025-06-25 16:50:45.110 | │    694 │   │   """Stop running the event loop.                               │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
    2025-06-25 16:50:45.110 | │ │   future = <Task finished name='functools'                               │ │
    2025-06-25 16:50:45.110 | │ │            coro=<AsyncIOBackend.run.<locals>.wrapper() done, defined at  │ │
    2025-06-25 16:50:45.110 | │ │            /usr/local/lib/python3.12/site-packages/anyio/_backends/_asy… │ │
    2025-06-25 16:50:45.110 | │ │            exception=TypeError("FastMCP.run_stdio_async() got an         │ │
    2025-06-25 16:50:45.110 | │ │            unexpected keyword argument 'log_level'")>                    │ │
    2025-06-25 16:50:45.110 | │ │ new_task = False                                                         │ │
    2025-06-25 16:50:45.110 | │ │     self = <_UnixSelectorEventLoop running=False closed=True             │ │
    2025-06-25 16:50:45.110 | │ │            debug=False>                                                  │ │
    2025-06-25 16:50:45.110 | │ ╰──────────────────────────────────────────────────────────────────────────╯ │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ /usr/local/lib/python3.12/site-packages/anyio/_backends/_asyncio.py:2298 in  │
    2025-06-25 16:50:45.110 | │ wrapper                                                                      │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │   2295 │   │   │   _task_states[task] = TaskState(None, None)                │
    2025-06-25 16:50:45.110 | │   2296 │   │   │                                                             │
    2025-06-25 16:50:45.110 | │   2297 │   │   │   try:                                                      │
    2025-06-25 16:50:45.110 | │ ❱ 2298 │   │   │   │   return await func(*args)                              │
    2025-06-25 16:50:45.110 | │   2299 │   │   │   finally:                                                  │
    2025-06-25 16:50:45.110 | │   2300 │   │   │   │   del _task_states[task]                                │
    2025-06-25 16:50:45.110 | │   2301                                                                       │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ ╭───────────────────────────────── locals ─────────────────────────────────╮ │
    2025-06-25 16:50:45.110 | │ │ args = ()                                                                │ │
    2025-06-25 16:50:45.110 | │ │ func = functools.partial(<bound method FastMCP.run_async of              │ │
    2025-06-25 16:50:45.110 | │ │        FastMCP('Basic Memory')>, 'stdio', log_level='INFO')              │ │
    2025-06-25 16:50:45.110 | │ │ task = <Task finished name='functools'                                   │ │
    2025-06-25 16:50:45.110 | │ │        coro=<AsyncIOBackend.run.<locals>.wrapper() done, defined at      │ │
    2025-06-25 16:50:45.110 | │ │        /usr/local/lib/python3.12/site-packages/anyio/_backends/_asyncio… │ │
    2025-06-25 16:50:45.110 | │ │        exception=TypeError("FastMCP.run_stdio_async() got an unexpected  │ │
    2025-06-25 16:50:45.110 | │ │        keyword argument 'log_level'")>                                   │ │
    2025-06-25 16:50:45.110 | │ ╰──────────────────────────────────────────────────────────────────────────╯ │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ /usr/local/lib/python3.12/site-packages/fastmcp/server/server.py:298 in      │
    2025-06-25 16:50:45.110 | │ run_async                                                                    │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │    295 │   │   │   raise ValueError(f"Unknown transport: {transport}")       │
    2025-06-25 16:50:45.110 | │    296 │   │                                                                 │
    2025-06-25 16:50:45.110 | │    297 │   │   if transport == "stdio":                                      │
    2025-06-25 16:50:45.110 | │ ❱  298 │   │   │   await self.run_stdio_async(**transport_kwargs)            │
    2025-06-25 16:50:45.110 | │    299 │   │   elif transport in {"http", "sse", "streamable-http"}:         │
    2025-06-25 16:50:45.110 | │    300 │   │   │   await self.run_http_async(transport=transport, **transpor │
    2025-06-25 16:50:45.110 | │    301 │   │   else:                                                         │
    2025-06-25 16:50:45.110 | │                                                                              │
    2025-06-25 16:50:45.110 | │ ╭────────────────── locals ──────────────────╮                               │
    2025-06-25 16:50:45.110 | │ │             self = FastMCP('Basic Memory') │                               │
    2025-06-25 16:50:45.110 | │ │        transport = 'stdio'                 │                               │
    2025-06-25 16:50:45.110 | │ │ transport_kwargs = {'log_level': 'INFO'}   │                               │
    2025-06-25 16:50:45.110 | │ ╰────────────────────────────────────────────╯                               │
    2025-06-25 16:50:45.110 | ╰──────────────────────────────────────────────────────────────────────────────╯
    2025-06-25 16:50:45.110 | TypeError: FastMCP.run_stdio_async() got an unexpected keyword argument 
    2025-06-25 16:50:45.110 | 'log_level'
    
  5. phernandez commented on Jun 25, 2025

    @phernandez
    Member

    @claude can you look at the user the error is reporting an come up with a suggestion?

  6. claude commented on Jun 25, 2025

    @claude
    Contributor

    Claude finished @phernandez's task —— View job


    Analyzing MCP Server Compatibility Issue

    I've analyzed the FastMCP 2.8.1 compatibility issue and identified the root cause and solution.

    Todo List:

    • Read current MCP server implementation
    • Analyze FastMCP version compatibility
    • Propose backward-compatible solution
    • Provide specific code recommendations

    Root Cause Analysis

    The issue occurs in src/basic_memory/cli/commands/mcp.py at lines 79 and 89 where mcp_server.run() is called with log_level="INFO":

    mcp_server.run(
        transport=transport,
        log_level="INFO",  # This parameter is not supported in FastMCP 2.8.1
    )

    The Problem:

    1. The log_level parameter was added to fix deprecation warnings (as mentioned in commit 7be001c)
    2. FastMCP 2.8.1 doesn't support the log_level parameter in its run_stdio_async() method
    3. This causes: TypeError: FastMCP.run_stdio_async() got an unexpected keyword argument 'log_level'
    4. Simply removing log_level causes the server to loop infinitely because the underlying issue isn't addressed

    Current Constraint:

    • The project requires fastmcp>=2.3.4 in pyproject.toml (line 33)
    • User is running FastMCP 2.8.1 which has API changes from earlier versions

    Proposed Solution

    I recommend implementing a version-aware parameter handling approach. Here are the options:

    Option 1: Version Detection (Recommended)

    import inspect
    from fastmcp import FastMCP
    
    def get_supported_run_params(transport: str) -> dict:
        """Get supported parameters for FastMCP.run() based on version/API."""
        if transport == "stdio":
            # Check if run_stdio_async supports log_level
            run_method = getattr(mcp_server, 'run_stdio_async', None)
            if run_method and 'log_level' in inspect.signature(run_method).parameters:
                return {"log_level": "INFO"}
        elif transport in ["streamable-http", "sse"]:
            # Check if run_http_async supports log_level  
            run_method = getattr(mcp_server, 'run_http_async', None)
            if run_method and 'log_level' in inspect.signature(run_method).parameters:
                return {"log_level": "INFO"}
        
        return {}
    
    # Usage:
    extra_params = get_supported_run_params(transport)
    if transport == "stdio":
        mcp_server.run(transport=transport, **extra_params)
    elif transport in ["streamable-http", "sse"]:
        mcp_server.run(transport=transport, host=host, port=port, path=path, **extra_params)

    Option 2: Try/Except Approach (Simpler)

    def run_mcp_server_safely(transport: str, **kwargs):
        """Run MCP server with graceful parameter handling."""
        try:
            mcp_server.run(transport=transport, log_level="INFO", **kwargs)
        except TypeError as e:
            if "unexpected keyword argument 'log_level'" in str(e):
                # Fallback: run without log_level parameter
                logger.warning("FastMCP version doesn't support log_level parameter, running without it")
                mcp_server.run(transport=transport, **kwargs)
            else:
                raise

    Option 3: Pin FastMCP Version (Conservative)

    Update pyproject.toml to pin to a specific version range that supports log_level:

    "fastmcp>=2.3.4,<2.8.0",  # Exclude versions that don't support log_level

    Recommendation

    I recommend Option 1 (Version Detection) because:

    • It's future-proof and works with any FastMCP version
    • It maintains the logging functionality when available
    • It doesn't restrict the FastMCP version unnecessarily
    • It follows Python best practices for API compatibility

    Would you like me to implement this solution?


  7. phernandez commented on Jun 26, 2025

    @phernandez
    Member

    I'm fixing this right now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions