diff --git a/src/git/README.md b/src/git/README.md index a252a4a7ba..92720d81f9 100644 --- a/src/git/README.md +++ b/src/git/README.md @@ -6,6 +6,8 @@ A Model Context Protocol server for Git repository interaction and automation. This server provides tools to read, search, and manipulate Git repositories via Large Language Models. +This package targets MCP Python SDK v2 (`mcp>=2,<3`). + Source: https://github.com/modelcontextprotocol/servers/tree/main/src/git Please note that mcp-server-git is currently in early development. The functionality and available tools are subject to change and expansion as we continue to develop and improve the server. diff --git a/src/git/pyproject.toml b/src/git/pyproject.toml index c5113ae7d4..11ecc45974 100644 --- a/src/git/pyproject.toml +++ b/src/git/pyproject.toml @@ -18,7 +18,7 @@ classifiers = [ dependencies = [ "click>=8.1.7", "gitpython>=3.1.50", - "mcp>=1.0.0", + "mcp>=2,<3", "pydantic>=2.0.0", ] diff --git a/src/git/src/mcp_server_git/server.py b/src/git/src/mcp_server_git/server.py index 84188d8fd7..914174190d 100644 --- a/src/git/src/mcp_server_git/server.py +++ b/src/git/src/mcp_server_git/server.py @@ -1,15 +1,18 @@ import logging from pathlib import Path -from typing import Sequence, Optional -from mcp.server import Server -from mcp.server.session import ServerSession +from typing import Any, Optional, Sequence +from mcp.server import Server, ServerRequestContext from mcp.server.stdio import stdio_server from mcp.types import ( + CallToolRequestParams, + CallToolResult, ClientCapabilities, - TextContent, - Tool, ListRootsResult, + ListToolsResult, + PaginatedRequestParams, RootsCapability, + TextContent, + Tool, ToolAnnotations, ) from enum import Enum @@ -316,156 +319,155 @@ async def serve(repository: Path | None) -> None: logger.error(f"{repository} is not a valid Git repository") return - server = Server("mcp-git") - - @server.list_tools() - async def list_tools() -> list[Tool]: - return [ + async def on_list_tools( + _ctx: ServerRequestContext[dict[str, Any]], + _params: PaginatedRequestParams | None, + ) -> ListToolsResult: + return ListToolsResult( + tools=[ Tool( name=GitTools.STATUS, description="Shows the working tree status", - inputSchema=GitStatus.model_json_schema(), + input_schema=GitStatus.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=True, - destructiveHint=False, - idempotentHint=True, - openWorldHint=False, + read_only_hint=True, + destructive_hint=False, + idempotent_hint=True, + open_world_hint=False, ), ), Tool( name=GitTools.DIFF_UNSTAGED, description="Shows changes in the working directory that are not yet staged", - inputSchema=GitDiffUnstaged.model_json_schema(), + input_schema=GitDiffUnstaged.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=True, - destructiveHint=False, - idempotentHint=True, - openWorldHint=False, + read_only_hint=True, + destructive_hint=False, + idempotent_hint=True, + open_world_hint=False, ), ), Tool( name=GitTools.DIFF_STAGED, description="Shows changes that are staged for commit", - inputSchema=GitDiffStaged.model_json_schema(), + input_schema=GitDiffStaged.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=True, - destructiveHint=False, - idempotentHint=True, - openWorldHint=False, + read_only_hint=True, + destructive_hint=False, + idempotent_hint=True, + open_world_hint=False, ), ), Tool( name=GitTools.DIFF, description="Shows differences between branches or commits", - inputSchema=GitDiff.model_json_schema(), + input_schema=GitDiff.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=True, - destructiveHint=False, - idempotentHint=True, - openWorldHint=False, + read_only_hint=True, + destructive_hint=False, + idempotent_hint=True, + open_world_hint=False, ), ), Tool( name=GitTools.COMMIT, description="Records changes to the repository", - inputSchema=GitCommit.model_json_schema(), + input_schema=GitCommit.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=False, - destructiveHint=False, - idempotentHint=False, - openWorldHint=False, + read_only_hint=False, + destructive_hint=False, + idempotent_hint=False, + open_world_hint=False, ), ), Tool( name=GitTools.ADD, description="Adds file contents to the staging area", - inputSchema=GitAdd.model_json_schema(), + input_schema=GitAdd.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=False, - destructiveHint=False, - idempotentHint=True, - openWorldHint=False, + read_only_hint=False, + destructive_hint=False, + idempotent_hint=True, + open_world_hint=False, ), ), Tool( name=GitTools.RESET, description="Unstages all staged changes", - inputSchema=GitReset.model_json_schema(), + input_schema=GitReset.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=False, - destructiveHint=True, - idempotentHint=True, - openWorldHint=False, + read_only_hint=False, + destructive_hint=True, + idempotent_hint=True, + open_world_hint=False, ), ), Tool( name=GitTools.LOG, description="Shows the commit logs", - inputSchema=GitLog.model_json_schema(), + input_schema=GitLog.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=True, - destructiveHint=False, - idempotentHint=True, - openWorldHint=False, + read_only_hint=True, + destructive_hint=False, + idempotent_hint=True, + open_world_hint=False, ), ), Tool( name=GitTools.CREATE_BRANCH, description="Creates a new branch from an optional base branch", - inputSchema=GitCreateBranch.model_json_schema(), + input_schema=GitCreateBranch.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=False, - destructiveHint=False, - idempotentHint=False, - openWorldHint=False, + read_only_hint=False, + destructive_hint=False, + idempotent_hint=False, + open_world_hint=False, ), ), Tool( name=GitTools.CHECKOUT, description="Switches branches", - inputSchema=GitCheckout.model_json_schema(), + input_schema=GitCheckout.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=False, - destructiveHint=False, - idempotentHint=False, - openWorldHint=False, + read_only_hint=False, + destructive_hint=False, + idempotent_hint=False, + open_world_hint=False, ), ), Tool( name=GitTools.SHOW, description="Shows the contents of a commit", - inputSchema=GitShow.model_json_schema(), + input_schema=GitShow.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=True, - destructiveHint=False, - idempotentHint=True, - openWorldHint=False, + read_only_hint=True, + destructive_hint=False, + idempotent_hint=True, + open_world_hint=False, ), ), Tool( name=GitTools.BRANCH, description="List Git branches", - inputSchema=GitBranch.model_json_schema(), + input_schema=GitBranch.model_json_schema(), annotations=ToolAnnotations( - readOnlyHint=True, - destructiveHint=False, - idempotentHint=True, - openWorldHint=False, + read_only_hint=True, + destructive_hint=False, + idempotent_hint=True, + open_world_hint=False, ), ) - ] + ] + ) - async def list_repos() -> Sequence[str]: + async def list_repos(ctx: ServerRequestContext[dict[str, Any]]) -> Sequence[str]: async def by_roots() -> Sequence[str]: - if not isinstance(server.request_context.session, ServerSession): - raise TypeError("server.request_context.session must be a ServerSession") - - if not server.request_context.session.check_client_capability( + if not ctx.session.check_client_capability( ClientCapabilities(roots=RootsCapability()) ): return [] - roots_result: ListRootsResult = await server.request_context.session.list_roots() + roots_result: ListRootsResult = await ctx.session.list_roots() logger.debug(f"Roots result: {roots_result}") repo_paths = [] for root in roots_result.roots: @@ -484,8 +486,11 @@ def by_commandline() -> Sequence[str]: root_repos = await by_roots() return [*root_repos, *cmd_repos] - @server.call_tool() - async def call_tool(name: str, arguments: dict) -> list[TextContent]: + async def on_call_tool( + _ctx: ServerRequestContext[dict[str, Any]], + params: CallToolRequestParams, + ) -> CallToolResult: + arguments = params.arguments or {} repo_path = Path(arguments["repo_path"]) # Validate repo_path is within allowed repository @@ -494,108 +499,98 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent]: # For all commands, we need an existing repo repo = git.Repo(repo_path) - match name: + match params.name: case GitTools.STATUS: status = git_status(repo) - return [TextContent( - type="text", - text=f"Repository status:\n{status}" - )] + return CallToolResult( + content=[TextContent(type="text", text=f"Repository status:\n{status}")] + ) case GitTools.DIFF_UNSTAGED: - diff = git_diff_unstaged(repo, arguments.get("context_lines", DEFAULT_CONTEXT_LINES)) - return [TextContent( - type="text", - text=f"Unstaged changes:\n{diff}" - )] + context_lines = arguments.get("context_lines", DEFAULT_CONTEXT_LINES) + diff = git_diff_unstaged(repo, context_lines) + return CallToolResult( + content=[TextContent(type="text", text=f"Unstaged changes:\n{diff}")] + ) case GitTools.DIFF_STAGED: - diff = git_diff_staged(repo, arguments.get("context_lines", DEFAULT_CONTEXT_LINES)) - return [TextContent( - type="text", - text=f"Staged changes:\n{diff}" - )] + context_lines = arguments.get("context_lines", DEFAULT_CONTEXT_LINES) + diff = git_diff_staged(repo, context_lines) + return CallToolResult( + content=[TextContent(type="text", text=f"Staged changes:\n{diff}")] + ) case GitTools.DIFF: - diff = git_diff(repo, arguments["target"], arguments.get("context_lines", DEFAULT_CONTEXT_LINES)) - return [TextContent( - type="text", - text=f"Diff with {arguments['target']}:\n{diff}" - )] + context_lines = arguments.get("context_lines", DEFAULT_CONTEXT_LINES) + diff = git_diff(repo, arguments["target"], context_lines) + return CallToolResult( + content=[ + TextContent( + type="text", + text=f"Diff with {arguments['target']}:\n{diff}", + ) + ] + ) case GitTools.COMMIT: result = git_commit(repo, arguments["message"]) - return [TextContent( - type="text", - text=result - )] + return CallToolResult(content=[TextContent(type="text", text=result)]) case GitTools.ADD: result = git_add(repo, arguments["files"]) - return [TextContent( - type="text", - text=result - )] + return CallToolResult(content=[TextContent(type="text", text=result)]) case GitTools.RESET: result = git_reset(repo) - return [TextContent( - type="text", - text=result - )] + return CallToolResult(content=[TextContent(type="text", text=result)]) - # Update the LOG case: case GitTools.LOG: log = git_log( repo, arguments.get("max_count", 10), arguments.get("start_timestamp"), - arguments.get("end_timestamp") + arguments.get("end_timestamp"), + ) + return CallToolResult( + content=[TextContent(type="text", text="Commit history:\n" + "\n".join(log))] ) - return [TextContent( - type="text", - text="Commit history:\n" + "\n".join(log) - )] case GitTools.CREATE_BRANCH: result = git_create_branch( repo, arguments["branch_name"], - arguments.get("base_branch") + arguments.get("base_branch"), ) - return [TextContent( - type="text", - text=result - )] + return CallToolResult(content=[TextContent(type="text", text=result)]) case GitTools.CHECKOUT: result = git_checkout(repo, arguments["branch_name"]) - return [TextContent( - type="text", - text=result - )] + return CallToolResult(content=[TextContent(type="text", text=result)]) case GitTools.SHOW: result = git_show(repo, arguments["revision"]) - return [TextContent( - type="text", - text=result - )] + return CallToolResult(content=[TextContent(type="text", text=result)]) case GitTools.BRANCH: result = git_branch( repo, - arguments.get("branch_type", 'local'), + arguments.get("branch_type", "local"), arguments.get("contains", None), arguments.get("not_contains", None), ) - return [TextContent( - type="text", - text=result - )] + return CallToolResult(content=[TextContent(type="text", text=result)]) case _: - raise ValueError(f"Unknown tool: {name}") + return CallToolResult( + content=[TextContent(type="text", text=f"Unknown tool: {params.name}")], + is_error=True, + ) + + server = Server( + name="mcp-git", + on_list_tools=on_list_tools, + on_call_tool=on_call_tool, + ) options = server.create_initialization_options() async with stdio_server() as (read_stream, write_stream): diff --git a/src/git/uv.lock b/src/git/uv.lock index a838e3d10d..63f27cd671 100644 --- a/src/git/uv.lock +++ b/src/git/uv.lock @@ -1,6 +1,10 @@ version = 1 revision = 3 requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.14'", + "python_full_version < '3.14'", +] [[package]] name = "annotated-types" @@ -13,17 +17,16 @@ wheels = [ [[package]] name = "anyio" -version = "4.6.2.post1" +version = "4.14.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422, upload-time = "2024-10-14T14:31:44.021Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377, upload-time = "2024-10-14T14:31:42.623Z" }, + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, ] [[package]] @@ -35,15 +38,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, ] -[[package]] -name = "certifi" -version = "2024.8.30" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507, upload-time = "2024-08-30T01:55:04.365Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321, upload-time = "2024-08-30T01:55:02.591Z" }, -] - [[package]] name = "cffi" version = "2.0.0" @@ -247,41 +241,32 @@ wheels = [ ] [[package]] -name = "httpcore" -version = "1.0.9" +name = "httpcore2" +version = "2.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "certifi" }, { name = "h11" }, + { name = "truststore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +sdist = { url = "https://files.pythonhosted.org/packages/39/a8/20ed1ed79cbc2ecdf5301c0968ab7c85547212e2a7bd126ddd2d986e206e/httpcore2-2.9.1.tar.gz", hash = "sha256:4d8acbf8b306f48c9d6046591fd5ba4037d1b1b1000d140fc2c3eab1e9a0c0e2", size = 67089, upload-time = "2026-07-24T09:21:03.867Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, + { url = "https://files.pythonhosted.org/packages/9f/fb/46c52b781975c335a2bcf1072c7bbc007cbdc8d674217f5ee1daba2c848b/httpcore2-2.9.1-py3-none-any.whl", hash = "sha256:6182472379e855fe4221246a2bb7ecede403bc61c6798062ae1787d051ccde26", size = 82809, upload-time = "2026-07-24T09:21:01.178Z" }, ] [[package]] -name = "httpx" -version = "0.27.2" +name = "httpx2" +version = "2.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, + { name = "httpcore2" }, { name = "idna" }, - { name = "sniffio" }, + { name = "truststore" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189, upload-time = "2024-08-27T12:54:01.334Z" } +sdist = { url = "https://files.pythonhosted.org/packages/21/14/38128fbafd7e0ed41d874df6c9a653d47c2d111cfe59e2b4ac95161b4abd/httpx2-2.9.1.tar.gz", hash = "sha256:1932a768737e3666291582833da748cc4e563c337cf96706fccc04fa6e58764a", size = 95458, upload-time = "2026-07-24T09:21:04.972Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395, upload-time = "2024-08-27T12:53:59.653Z" }, -] - -[[package]] -name = "httpx-sse" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624, upload-time = "2023-12-22T08:01:21.083Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819, upload-time = "2023-12-22T08:01:19.89Z" }, + { url = "https://files.pythonhosted.org/packages/13/b8/cfd91c4ab9134d386d48f0b6ac662ff3d4be6efdee59ee1c67ebc3c0487c/httpx2-2.9.1-py3-none-any.whl", hash = "sha256:1820fe14a9ab1107bfeff39259987429450b070ec0ff38cc87eb0d8c97fdc71a", size = 91191, upload-time = "2026-07-24T09:21:02.6Z" }, ] [[package]] @@ -331,15 +316,15 @@ wheels = [ [[package]] name = "mcp" -version = "1.23.0" +version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, - { name = "httpx" }, - { name = "httpx-sse" }, + { name = "httpx2" }, { name = "jsonschema" }, + { name = "mcp-types" }, + { name = "opentelemetry-api" }, { name = "pydantic" }, - { name = "pydantic-settings" }, { name = "pyjwt", extra = ["crypto"] }, { name = "python-multipart" }, { name = "pywin32", marker = "sys_platform == 'win32'" }, @@ -349,9 +334,9 @@ dependencies = [ { name = "typing-inspection" }, { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/25/1a/9c8a5362e3448d585081d6c7aa95898a64e0ac59d3e26169ae6c3ca5feaf/mcp-1.23.0.tar.gz", hash = "sha256:84e0c29316d0a8cf0affd196fd000487ac512aa3f771b63b2ea864e22961772b", size = 596506, upload-time = "2025-12-02T13:40:02.558Z" } +sdist = { url = "https://files.pythonhosted.org/packages/74/33/32d4dff2c95bb5d897c3ef4c83649a08996b17b58f0a326d2495d4c81179/mcp-2.0.0.tar.gz", hash = "sha256:0f440e735c13ece8bb19bc62cf0b86f4313448432fbb77d35e14034f4e050728", size = 1662284, upload-time = "2026-07-28T13:45:32.346Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/b2/28739ce409f98159c0121eab56e69ad71546c4f34ac8b42e58c03f57dccc/mcp-1.23.0-py3-none-any.whl", hash = "sha256:5a645cf111ed329f4619f2629a3f15d9aabd7adc2ea09d600d31467b51ecb64f", size = 231427, upload-time = "2025-12-02T13:40:00.738Z" }, + { url = "https://files.pythonhosted.org/packages/67/72/7d7897418912c1d12e87556630dfb7bf0eac71160e9bef8b447960804ee3/mcp-2.0.0-py3-none-any.whl", hash = "sha256:1cb4c75d2d2c7b8c1d756355e5d82a39f2822cc7f13e22a2051d7ca3592349d6", size = 349980, upload-time = "2026-07-28T13:45:28.853Z" }, ] [[package]] @@ -376,7 +361,7 @@ dev = [ requires-dist = [ { name = "click", specifier = ">=8.1.7" }, { name = "gitpython", specifier = ">=3.1.50" }, - { name = "mcp", specifier = ">=1.0.0" }, + { name = "mcp", specifier = ">=2,<3" }, { name = "pydantic", specifier = ">=2.0.0" }, ] @@ -387,6 +372,19 @@ dev = [ { name = "ruff", specifier = ">=0.7.3" }, ] +[[package]] +name = "mcp-types" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/56/9b8e1c152f61f6c6b07c4b5896c88c7d0ae90bac6ee6306f852fcc5c1eb0/mcp_types-2.0.0.tar.gz", hash = "sha256:d7d939b9285c9961ae8866ba75ef85da34d12bafe276efbf4eb6a131786d8379", size = 66632, upload-time = "2026-07-28T13:45:33.804Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/4c/c78d78c3d52b0ac594ad7cc8ef5972adfe070e3597a8a4c6ce0cd39196ea/mcp_types-2.0.0-py3-none-any.whl", hash = "sha256:6b2de797ca2797f568b79529e1b25948e34de511bcc0bd82fef1039a6d1b8eb0", size = 69649, upload-time = "2026-07-28T13:45:30.713Z" }, +] + [[package]] name = "nodeenv" version = "1.9.1" @@ -396,6 +394,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, ] +[[package]] +name = "opentelemetry-api" +version = "1.44.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ee/8b/aa9e2d8b8dfa7c946f7dec5d1f8f6ba8eca062f43509a06bdb5ce93d26c0/opentelemetry_api-1.44.0.tar.gz", hash = "sha256:67647e5e9566edcf421166fdf022b3537f818635daa852b289e34604dc6fb33a", size = 72406, upload-time = "2026-07-16T15:25:32.678Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/6f/a04e900f465ff3221ccc395522503e2d10e79fa21f2723c8e177aae1e0d1/opentelemetry_api-1.44.0-py3-none-any.whl", hash = "sha256:94b98c893a91b88657eaac1e3ba89618cdb85be6918196705354f34728b2cdef", size = 60018, upload-time = "2026-07-16T15:25:11.657Z" }, +] + [[package]] name = "packaging" version = "24.2" @@ -556,20 +566,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, ] -[[package]] -name = "pydantic-settings" -version = "2.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, -] - [[package]] name = "pygments" version = "2.20.0" @@ -627,15 +623,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d4/24/a372aaf5c9b7208e7112038812994107bc65a84cd00e0354a88c2c77a617/pytest-9.0.3-py3-none-any.whl", hash = "sha256:2c5efc453d45394fdd706ade797c0a81091eccd1d6e4bccfcd476e2b8e0ab5d9", size = 375249, upload-time = "2026-04-07T17:16:16.13Z" }, ] -[[package]] -name = "python-dotenv" -version = "1.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, -] - [[package]] name = "python-multipart" version = "0.0.32" @@ -837,27 +824,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a7/a5/10f97f73544edcdef54409f1d839f6049a0d79df68adbc1ceb24d1aaca42/smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da", size = 24282, upload-time = "2023-09-17T11:35:03.253Z" }, ] -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - [[package]] name = "sse-starlette" -version = "2.1.3" +version = "3.4.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "starlette" }, - { name = "uvicorn" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/fc/56ab9f116b2133521f532fce8d03194cf04dcac25f583cf3d839be4c0496/sse_starlette-2.1.3.tar.gz", hash = "sha256:9cd27eb35319e1414e3d2558ee7414487f9529ce3b3cf9b21434fd110e017169", size = 19678, upload-time = "2024-08-01T08:52:50.248Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/10/a34c656829ffc1c4b22ef36d70d9ebb6b99c020e2aeb17cee5485099f028/sse_starlette-3.4.6.tar.gz", hash = "sha256:725f8a1bd6d26ae1b2c9610c0ef5065dfdd496f3988d28adcf8c4b49dc25c627", size = 32542, upload-time = "2026-07-20T14:16:32.201Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/52/aa/36b271bc4fa1d2796311ee7c7283a3a1c348bad426d37293609ca4300eef/sse_starlette-2.1.3-py3-none-any.whl", hash = "sha256:8ec846438b4665b9e8c560fcdea6bc8081a3abf7942faa95e5a744999d219772", size = 9383, upload-time = "2024-08-01T08:52:48.659Z" }, + { url = "https://files.pythonhosted.org/packages/49/36/e10c1d1b7ca881d2625db2ec28508578499187bb1c389952c398474e1834/sse_starlette-3.4.6-py3-none-any.whl", hash = "sha256:56217ab4c9a9f9c5db7b21e08732d3e7c2b807f45231ad23de0551a24c4a41f6", size = 16516, upload-time = "2026-07-20T14:16:30.978Z" }, ] [[package]] @@ -912,6 +889,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, ] +[[package]] +name = "truststore" +version = "0.10.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/a3/1585216310e344e8102c22482f6060c7a6ea0322b63e026372e6dcefcfd6/truststore-0.10.4.tar.gz", hash = "sha256:9d91bd436463ad5e4ee4aba766628dd6cd7010cf3e2461756b3303710eebc301", size = 26169, upload-time = "2025-08-12T18:49:02.73Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/97/56608b2249fe206a67cd573bc93cd9896e1efb9e98bce9c163bcdc704b88/truststore-0.10.4-py3-none-any.whl", hash = "sha256:adaeaecf1cbb5f4de3b1959b42d41f6fab57b2b1666adb59e89cb0b53361d981", size = 18660, upload-time = "2025-08-12T18:49:01.46Z" }, +] + [[package]] name = "typing-extensions" version = "4.15.0"