aiohttp-tiny-mcp 0.3.6__tar.gz → 0.3.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/PKG-INFO +1 -1
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/pyproject.toml +1 -1
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/pyproject.toml.orig +1 -1
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/endpoint.py +3 -8
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/extensions.py +2 -1
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/http_sse.py +2 -6
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/stdio.py +4 -2
- aiohttp_tiny_mcp-0.3.7/src/aiohttp_tiny_mcp/tasks.py +37 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/LICENSE +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/README.md +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/__init__.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/adapter.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/auth.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/client.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/client_base.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/console/__init__.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/console/console.css +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/console/console.js +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/console/index.html +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/core.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/dispatcher.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/exchange.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/hub.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/models.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/namespaces.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/postgres.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/__init__.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/selection.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/v2024_11_05.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/v2025_03_26.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/v2025_06_18.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/v2025_11_25.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/v2026_07_28.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/py.typed +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/redis.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/registry.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/request_state.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/schema.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/sessions.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/skills.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/specs.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/sqlite.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/sse.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/stdio_client.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/subscriptions.py +0 -0
- {aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/testing.py +0 -0
|
@@ -7,7 +7,6 @@ import json
|
|
|
7
7
|
import logging
|
|
8
8
|
import re
|
|
9
9
|
from collections.abc import Mapping
|
|
10
|
-
from contextlib import suppress
|
|
11
10
|
from dataclasses import replace
|
|
12
11
|
from functools import cached_property
|
|
13
12
|
from typing import Any
|
|
@@ -46,6 +45,7 @@ from .sessions import (
|
|
|
46
45
|
)
|
|
47
46
|
from .sse import SSEResponse
|
|
48
47
|
from .subscriptions import relays, wanted
|
|
48
|
+
from .tasks import stop
|
|
49
49
|
|
|
50
50
|
log = logging.getLogger("aiohttp_tiny_mcp")
|
|
51
51
|
|
|
@@ -419,9 +419,7 @@ class Endpoint:
|
|
|
419
419
|
if transport is None or transport.is_closing():
|
|
420
420
|
break
|
|
421
421
|
finally:
|
|
422
|
-
relay
|
|
423
|
-
with suppress(asyncio.CancelledError, ConnectionError):
|
|
424
|
-
await relay
|
|
422
|
+
await stop(relay)
|
|
425
423
|
return response
|
|
426
424
|
|
|
427
425
|
async def relay_notifications(
|
|
@@ -578,10 +576,7 @@ class Endpoint:
|
|
|
578
576
|
ex.cancel()
|
|
579
577
|
raise
|
|
580
578
|
finally:
|
|
581
|
-
|
|
582
|
-
task.cancel()
|
|
583
|
-
with suppress(asyncio.CancelledError):
|
|
584
|
-
await task
|
|
579
|
+
await stop(task)
|
|
585
580
|
|
|
586
581
|
|
|
587
582
|
MCP_ENDPOINT = web.AppKey("mcp_endpoint", Endpoint)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import dataclasses
|
|
5
6
|
import json
|
|
6
7
|
from collections.abc import Awaitable, Callable, Iterable, Mapping
|
|
7
8
|
from copy import deepcopy
|
|
@@ -57,7 +58,7 @@ class ExtensionSpec:
|
|
|
57
58
|
methods: Mapping[str, Bound]
|
|
58
59
|
#: Broadcast method to the params field that carries its topic, or None for one
|
|
59
60
|
#: every listener of the method gets.
|
|
60
|
-
notifications: Mapping[str, str | None] =
|
|
61
|
+
notifications: Mapping[str, str | None] = dataclasses.field(default_factory=dict)
|
|
61
62
|
|
|
62
63
|
|
|
63
64
|
class ExtensionResult(ResultModel):
|
|
@@ -6,7 +6,6 @@ import asyncio
|
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
8
|
from collections.abc import Coroutine
|
|
9
|
-
from contextlib import suppress
|
|
10
9
|
from dataclasses import replace
|
|
11
10
|
from typing import Any
|
|
12
11
|
|
|
@@ -41,6 +40,7 @@ from .sessions import (
|
|
|
41
40
|
)
|
|
42
41
|
from .sse import SSEResponse
|
|
43
42
|
from .subscriptions import relays, wanted
|
|
43
|
+
from .tasks import stop
|
|
44
44
|
|
|
45
45
|
log = logging.getLogger(__name__)
|
|
46
46
|
|
|
@@ -148,11 +148,7 @@ class SseEndpoint:
|
|
|
148
148
|
if transport is None or transport.is_closing():
|
|
149
149
|
break
|
|
150
150
|
finally:
|
|
151
|
-
|
|
152
|
-
task.cancel()
|
|
153
|
-
for task in tasks:
|
|
154
|
-
with suppress(asyncio.CancelledError, ConnectionError):
|
|
155
|
-
await task
|
|
151
|
+
await stop(*tasks)
|
|
156
152
|
|
|
157
153
|
async def relay(self, response: SSEResponse, events: Subscription) -> None:
|
|
158
154
|
"""Write everything published for this connection, until cancelled."""
|
|
@@ -11,6 +11,7 @@ import json
|
|
|
11
11
|
import logging
|
|
12
12
|
import sys
|
|
13
13
|
from collections.abc import Callable, Mapping
|
|
14
|
+
from contextlib import suppress
|
|
14
15
|
from dataclasses import replace
|
|
15
16
|
from typing import Any
|
|
16
17
|
|
|
@@ -26,6 +27,7 @@ from .dispatcher import Dispatcher
|
|
|
26
27
|
from .exchange import Exchange, is_reply, relay_reply
|
|
27
28
|
from .protocol.selection import AdapterSet
|
|
28
29
|
from .registry import Registry
|
|
30
|
+
from .tasks import stop
|
|
29
31
|
|
|
30
32
|
log = logging.getLogger("aiohttp_tiny_mcp")
|
|
31
33
|
|
|
@@ -155,9 +157,9 @@ async def serve_stdio(
|
|
|
155
157
|
tasks = []
|
|
156
158
|
for exchange, task in list(active.values()):
|
|
157
159
|
exchange.cancel()
|
|
158
|
-
task.cancel()
|
|
159
160
|
tasks.append(task)
|
|
160
|
-
|
|
161
|
+
with suppress(Exception):
|
|
162
|
+
await stop(*tasks)
|
|
161
163
|
|
|
162
164
|
|
|
163
165
|
async def stdin_reader() -> asyncio.StreamReader:
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Ending a task that may not honour its first cancellation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
STOP_GRACE_SECONDS = 1.0
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
async def stop(*tasks: asyncio.Task[Any], grace: float = STOP_GRACE_SECONDS) -> None:
|
|
12
|
+
"""Cancel `tasks` and return when every one of them has ended.
|
|
13
|
+
|
|
14
|
+
One cancellation is not always enough. A library may catch it, and on
|
|
15
|
+
Python before 3.12 `asyncio.wait_for` drops it when the future it waits
|
|
16
|
+
on completes in the same loop turn: psycopg_pool waits for a connection
|
|
17
|
+
that way, and a sibling task that is cancelled first hands its
|
|
18
|
+
connection back at exactly that moment. A task still running after
|
|
19
|
+
`grace` seconds is cancelled again, at whatever it awaits by then.
|
|
20
|
+
|
|
21
|
+
A cancelled task and one that ended with `ConnectionError` are what
|
|
22
|
+
stopping looks like. Any other exception is raised, the first one found.
|
|
23
|
+
"""
|
|
24
|
+
pending = {task for task in tasks if not task.done()}
|
|
25
|
+
while pending:
|
|
26
|
+
for task in pending:
|
|
27
|
+
task.cancel()
|
|
28
|
+
_, pending = await asyncio.wait(pending, timeout=grace)
|
|
29
|
+
for task in tasks:
|
|
30
|
+
if task.cancelled():
|
|
31
|
+
continue
|
|
32
|
+
error = task.exception()
|
|
33
|
+
if error is not None and not isinstance(error, ConnectionError):
|
|
34
|
+
raise error
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
__all__ = ["STOP_GRACE_SECONDS", "stop"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/selection.py
RENAMED
|
File without changes
|
{aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/v2024_11_05.py
RENAMED
|
File without changes
|
{aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/v2025_03_26.py
RENAMED
|
File without changes
|
{aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/v2025_06_18.py
RENAMED
|
File without changes
|
{aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/v2025_11_25.py
RENAMED
|
File without changes
|
{aiohttp_tiny_mcp-0.3.6 → aiohttp_tiny_mcp-0.3.7}/src/aiohttp_tiny_mcp/protocol/v2026_07_28.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|