Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "keboola-mcp-server"
version = "1.17.1"
version = "1.17.2"
description = "MCP server for interacting with Keboola Connection"
readme = "README.md"
requires-python = ">=3.10"
Expand Down
6 changes: 5 additions & 1 deletion src/keboola_mcp_server/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ async def run_server(args: Optional[list[str]] = None) -> None:
log_config = None

if log_config:
logging.config.fileConfig(log_config, disable_existing_loggers=False)
logging.config.fileConfig(log_config, disable_existing_loggers=True)
# disarm the 'FastMCP' logger; there is no legitimate way to configure this in fastmcp
fastmcp_logger = logging.getLogger('FastMCP')
fastmcp_logger.handlers.clear()
fastmcp_logger.propagate = True
else:
logging.basicConfig(
format='%(asctime)s %(name)s %(levelname)s: %(message)s',
Expand Down
35 changes: 35 additions & 0 deletions tests/test_server.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import json
import subprocess
import time
from dataclasses import asdict
from pathlib import Path
from typing import Annotated, Any

import pytest
Expand Down Expand Up @@ -232,3 +236,34 @@ async def assessed_function(ctx: Context, param: str) -> str:
result = await client.call_tool('assessed_function', {'param': 'value'})
assert isinstance(result.content[0], TextContent)
assert result.content[0].text == 'value'


def test_json_logging(mocker):
log_config_file = Path(__file__).parent.parent / 'logging-json.conf'
assert log_config_file.is_file(), f'No logging config file found at {log_config_file.absolute()}'

# start the MCP server process with json logging
p = subprocess.Popen(
['python', '-m', 'keboola_mcp_server', '--transport', 'sse', '--log-config', log_config_file.absolute()],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
# give the server time to fully start
time.sleep(5)

# kill the server and capture streams
p.kill()
stdout, stderr = p.communicate()

# there is only one handler (the root one) in logging-json.conf which sends messages to stdout
assert stderr == ''

# all messages should be JSON-formatted, including those logged by FastMCP loggers
fastmcp_startup_message: dict[str, Any] | None = None
for line in stdout.splitlines():
message = json.loads(line)
if message['message'].startswith('Starting MCP server') and message['name'].startswith('FastMCP.fastmcp'):
fastmcp_startup_message = message

assert fastmcp_startup_message is not None
Loading