Fix uv lock for time-server, update Readme

This commit is contained in:
Mariusz Korzekwa
2024-11-28 21:46:36 +01:00
parent 774cd0bd8e
commit d37ce3cc51
5 changed files with 21 additions and 124 deletions

View File

@@ -5,8 +5,8 @@ A Model Context Protocol server that provides time and timezone conversion capab
### Available Tools
- `get_current_time` - Get current time in a specific timezone or system timezone.
- Optional argument: `timezone` (string): IANA timezone name (e.g., 'America/New_York', 'Europe/London')
- If timezone is not provided, returns time in system timezone
- Required arguments:
- `timezone` (string): IANA timezone name (e.g., 'America/New_York', 'Europe/London')
- `convert_time` - Convert time between timezones.
- Required arguments:
@@ -111,45 +111,25 @@ Example:
## Example Interactions
1. Get current time (using system timezone):
```json
{
"name": "get_current_time",
"arguments": {}
}
```
Response:
```json
{
"timezone": "Europe/London",
"time": "14:30 BST",
"date": "2024-11-25",
"full_datetime": "2024-11-25 14:30:00 BST",
"is_dst": true
}
```
2. Get current time in specific timezone:
1. Get current time:
```json
{
"name": "get_current_time",
"arguments": {
"timezone": "America/New_York"
"timezone": "Europe/Warsaw"
}
}
```
Response:
```json
{
"timezone": "America/New_York",
"time": "09:30 EDT",
"date": "2024-11-25",
"full_datetime": "2024-11-25 09:30:00 EDT",
"is_dst": true
"timezone": "Europe/Warsaw",
"datetime": "2024-01-01T13:00:00+01:00",
"is_dst": false
}
```
3. Convert time between timezones:
2. Convert time between timezones:
```json
{
"name": "convert_time",
@@ -165,31 +145,18 @@ Response:
{
"source": {
"timezone": "America/New_York",
"time": "16:30 EDT",
"date": "2024-11-25"
"datetime": "2024-01-01T12:30:00-05:00",
"is_dst": false
},
"target": {
"timezone": "Asia/Tokyo",
"time": "05:30 JST",
"date": "2024-11-26"
"datetime": "2024-01-01T12:30:00+09:00",
"is_dst": false
},
"time_difference": "+13.0h",
"date_changed": true,
"day_relation": "next day"
}
```
## Tips for Using IANA Timezone Names
Common timezone formats:
- North America: `America/New_York`, `America/Los_Angeles`, `America/Chicago`
- Europe: `Europe/London`, `Europe/Paris`, `Europe/Berlin`
- Asia: `Asia/Tokyo`, `Asia/Shanghai`, `Asia/Dubai`
- Pacific: `Pacific/Auckland`, `Pacific/Honolulu`
- Australia: `Australia/Sydney`, `Australia/Melbourne`
The server will automatically detect and use your system timezone if no specific timezone is provided.
## Debugging
You can use the MCP inspector to debug the server. For uvx installations:

View File

@@ -1,6 +1,6 @@
[project]
name = "mcp-server-time"
version = "0.5.1.pre3"
version = "0.5.1"
description = "A Model Context Protocol server providing tools for time queries and timezone conversions for LLMs"
readme = "README.md"
requires-python = ">=3.10"
@@ -33,5 +33,4 @@ dev-dependencies = [
"freezegun>=1.5.1",
"pyright>=1.1.389",
"pytest>=8.3.3",
"ruff>=0.7.3",
]

View File

@@ -1,5 +1,4 @@
from dataclasses import dataclass
from datetime import datetime, timedelta
from datetime import datetime
from enum import Enum
import json
from typing import Sequence
@@ -35,13 +34,10 @@ class TimeConversionInput(BaseModel):
time: str
target_tz_list: list[str]
def get_local_tz(local_tz_override: str | None = None) -> pytz.timezone:
return pytz.timezone(local_tz_override) if local_tz_override else get_localzone()
class TimeServer:
def __init__(self, local_tz_override: str | None = None):
self.local_tz = (
pytz.timezone(local_tz_override) if local_tz_override else get_localzone()
)
def get_current_time(self, timezone_name: str) -> TimeResult:
"""Get current time in specified timezone"""
try:
@@ -109,8 +105,8 @@ class TimeServer:
async def serve(local_timezone: str | None = None) -> None:
server = Server("mcp-time")
time_server = TimeServer(local_timezone)
local_tz = str(time_server.local_tz)
time_server = TimeServer()
local_tz = str(get_local_tz(local_timezone))
@server.list_tools()
async def list_tools() -> list[Tool]:
@@ -183,7 +179,7 @@ async def serve(local_timezone: str | None = None) -> None:
case _:
raise ValueError(f"Unknown tool: {name}")
return [TextContent(type="text", text=json.dumps(result, indent=2))]
return [TextContent(type="text", text=json.dumps(result.model_dump(), indent=2))]
except Exception as e:
raise ValueError(f"Error processing mcp-server-time query: {str(e)}")

View File

@@ -3,7 +3,7 @@ import os
from freezegun import freeze_time
import pytest
from mcp_server_time.server import TimeServer
from mcp_server_time.server import TimeServer, serve
@pytest.mark.parametrize(
@@ -455,41 +455,3 @@ def test_convert_time(test_time, source_tz, time_str, target_tz, expected):
assert result.source.is_dst == expected["source"]["is_dst"]
assert result.target.is_dst == expected["target"]["is_dst"]
assert result.time_difference == expected["time_difference"]
# @pytest.mark.anyio
# async def test_call_tool(mock_forecast_response):
# class Response():
# def raise_for_status(self):
# pass
# def json(self):
# return mock_forecast_response
# class AsyncClient():
# def __aenter__(self):
# return self
# async def __aexit__(self, *exc_info):
# pass
# async def get(self, *args, **kwargs):
# return Response()
# with patch('httpx.AsyncClient', new=AsyncClient) as mock_client:
# result = await call_tool("get_forecast", {"city": "London", "days": 2})
# assert len(result) == 1
# assert result[0].type == "text"
# forecast_data = json.loads(result[0].text)
# assert len(forecast_data) == 1
# assert forecast_data[0]["temperature"] == 18.5
# assert forecast_data[0]["conditions"] == "sunny"
# @pytest.mark.anyio
# async def test_list_tools():
# tools = await list_tools()
# assert len(tools) == 1
# assert tools[0].name == "get_forecast"
# assert "city" in tools[0].inputSchema["properties"]

29
src/time/uv.lock generated
View File

@@ -160,7 +160,7 @@ wheels = [
[[package]]
name = "mcp-server-time"
version = "0.5.1rc3"
version = "0.5.1"
source = { editable = "." }
dependencies = [
{ name = "mcp" },
@@ -174,7 +174,6 @@ dev = [
{ name = "freezegun" },
{ name = "pyright" },
{ name = "pytest" },
{ name = "ruff" },
]
[package.metadata]
@@ -190,7 +189,6 @@ dev = [
{ name = "freezegun", specifier = ">=1.5.1" },
{ name = "pyright", specifier = ">=1.1.389" },
{ name = "pytest", specifier = ">=8.3.3" },
{ name = "ruff", specifier = ">=0.7.3" },
]
[[package]]
@@ -360,31 +358,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/11/c3/005fcca25ce078d2cc29fd559379817424e94885510568bc1bc53d7d5846/pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725", size = 508002 },
]
[[package]]
name = "ruff"
version = "0.8.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/b2/d6/a2373f3ba7180ddb44420d2a9d1f1510e1a4d162b3d27282bedcb09c8da9/ruff-0.8.0.tar.gz", hash = "sha256:a7ccfe6331bf8c8dad715753e157457faf7351c2b69f62f32c165c2dbcbacd44", size = 3276537 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/ec/77/e889ee3ce7fd8baa3ed1b77a03b9fb8ec1be68be1418261522fd6a5405e0/ruff-0.8.0-py3-none-linux_armv6l.whl", hash = "sha256:fcb1bf2cc6706adae9d79c8d86478677e3bbd4ced796ccad106fd4776d395fea", size = 10518283 },
{ url = "https://files.pythonhosted.org/packages/da/c8/0a47de01edf19fb22f5f9b7964f46a68d0bdff20144d134556ffd1ba9154/ruff-0.8.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:295bb4c02d58ff2ef4378a1870c20af30723013f441c9d1637a008baaf928c8b", size = 10317691 },
{ url = "https://files.pythonhosted.org/packages/41/17/9885e4a0eeae07abd2a4ebabc3246f556719f24efa477ba2739146c4635a/ruff-0.8.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7b1f1c76b47c18fa92ee78b60d2d20d7e866c55ee603e7d19c1e991fad933a9a", size = 9940999 },
{ url = "https://files.pythonhosted.org/packages/3e/cd/46b6f7043597eb318b5f5482c8ae8f5491cccce771e85f59d23106f2d179/ruff-0.8.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb0d4f250a7711b67ad513fde67e8870109e5ce590a801c3722580fe98c33a99", size = 10772437 },
{ url = "https://files.pythonhosted.org/packages/5d/87/afc95aeb8bc78b1d8a3461717a4419c05aa8aa943d4c9cbd441630f85584/ruff-0.8.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e55cce9aa93c5d0d4e3937e47b169035c7e91c8655b0974e61bb79cf398d49c", size = 10299156 },
{ url = "https://files.pythonhosted.org/packages/65/fa/04c647bb809c4d65e8eae1ed1c654d9481b21dd942e743cd33511687b9f9/ruff-0.8.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f4cd64916d8e732ce6b87f3f5296a8942d285bbbc161acee7fe561134af64f9", size = 11325819 },
{ url = "https://files.pythonhosted.org/packages/90/26/7dad6e7d833d391a8a1afe4ee70ca6f36c4a297d3cca83ef10e83e9aacf3/ruff-0.8.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c5c1466be2a2ebdf7c5450dd5d980cc87c8ba6976fb82582fea18823da6fa362", size = 12023927 },
{ url = "https://files.pythonhosted.org/packages/24/a0/be5296dda6428ba8a13bda8d09fbc0e14c810b485478733886e61597ae2b/ruff-0.8.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2dabfd05b96b7b8f2da00d53c514eea842bff83e41e1cceb08ae1966254a51df", size = 11589702 },
{ url = "https://files.pythonhosted.org/packages/26/3f/7602eb11d2886db545834182a9dbe500b8211fcbc9b4064bf9d358bbbbb4/ruff-0.8.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:facebdfe5a5af6b1588a1d26d170635ead6892d0e314477e80256ef4a8470cf3", size = 12782936 },
{ url = "https://files.pythonhosted.org/packages/4c/5d/083181bdec4ec92a431c1291d3fff65eef3ded630a4b55eb735000ef5f3b/ruff-0.8.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87a8e86bae0dbd749c815211ca11e3a7bd559b9710746c559ed63106d382bd9c", size = 11138488 },
{ url = "https://files.pythonhosted.org/packages/b7/23/c12cdef58413cee2436d6a177aa06f7a366ebbca916cf10820706f632459/ruff-0.8.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:85e654f0ded7befe2d61eeaf3d3b1e4ef3894469cd664ffa85006c7720f1e4a2", size = 10744474 },
{ url = "https://files.pythonhosted.org/packages/29/61/a12f3b81520083cd7c5caa24ba61bb99fd1060256482eff0ef04cc5ccd1b/ruff-0.8.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:83a55679c4cb449fa527b8497cadf54f076603cc36779b2170b24f704171ce70", size = 10369029 },
{ url = "https://files.pythonhosted.org/packages/08/2a/c013f4f3e4a54596c369cee74c24870ed1d534f31a35504908b1fc97017a/ruff-0.8.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:812e2052121634cf13cd6fddf0c1871d0ead1aad40a1a258753c04c18bb71bbd", size = 10867481 },
{ url = "https://files.pythonhosted.org/packages/d5/f7/685b1e1d42a3e94ceb25eab23c70bdd8c0ab66a43121ef83fe6db5a58756/ruff-0.8.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:780d5d8523c04202184405e60c98d7595bdb498c3c6abba3b6d4cdf2ca2af426", size = 11237117 },
{ url = "https://files.pythonhosted.org/packages/03/20/401132c0908e8837625e3b7e32df9962e7cd681a4df1e16a10e2a5b4ecda/ruff-0.8.0-py3-none-win32.whl", hash = "sha256:5fdb6efecc3eb60bba5819679466471fd7d13c53487df7248d6e27146e985468", size = 8783511 },
{ url = "https://files.pythonhosted.org/packages/1d/5c/4d800fca7854f62ad77f2c0d99b4b585f03e2d87a6ec1ecea85543a14a3c/ruff-0.8.0-py3-none-win_amd64.whl", hash = "sha256:582891c57b96228d146725975fbb942e1f30a0c4ba19722e692ca3eb25cc9b4f", size = 9559876 },
{ url = "https://files.pythonhosted.org/packages/5b/bc/cc8a6a5ca4960b226dc15dd8fb511dd11f2014ff89d325c0b9b9faa9871f/ruff-0.8.0-py3-none-win_arm64.whl", hash = "sha256:ba93e6294e9a737cd726b74b09a6972e36bb511f9a102f1d9a7e1ce94dd206a6", size = 8939733 },
]
[[package]]
name = "six"
version = "1.16.0"