aiohttp-tiny-mcp 0.4.0__tar.gz → 0.4.1__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.
Files changed (52) hide show
  1. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/PKG-INFO +4 -4
  2. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/README.md +3 -3
  3. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/pyproject.toml +1 -1
  4. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/pyproject.toml.orig +1 -1
  5. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/console/__init__.py +21 -1
  6. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/console/console.css +9 -2
  7. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/console/console.js +420 -18
  8. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/console/index.html +36 -1
  9. aiohttp_tiny_mcp-0.4.1/src/aiohttp_tiny_mcp/console/oauth-callback.html +14 -0
  10. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/endpoint.py +7 -4
  11. aiohttp_tiny_mcp-0.4.1/src/aiohttp_tiny_mcp/metadata.py +44 -0
  12. aiohttp_tiny_mcp-0.4.1/src/aiohttp_tiny_mcp/oauth/__init__.py +15 -0
  13. aiohttp_tiny_mcp-0.4.1/src/aiohttp_tiny_mcp/oauth/facade.py +551 -0
  14. aiohttp_tiny_mcp-0.4.1/src/aiohttp_tiny_mcp/oauth/github.py +45 -0
  15. aiohttp_tiny_mcp-0.4.1/src/aiohttp_tiny_mcp/oauth/upstream.py +117 -0
  16. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/LICENSE +0 -0
  17. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/__init__.py +0 -0
  18. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/adapter.py +0 -0
  19. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/auth.py +0 -0
  20. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/client.py +0 -0
  21. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/client_base.py +0 -0
  22. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/core.py +0 -0
  23. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/dispatcher.py +0 -0
  24. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/exchange.py +0 -0
  25. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/extensions.py +0 -0
  26. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/http_sse.py +0 -0
  27. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/hub.py +0 -0
  28. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/models.py +0 -0
  29. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/namespaces.py +0 -0
  30. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/postgres.py +0 -0
  31. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/protocol/__init__.py +0 -0
  32. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/protocol/selection.py +0 -0
  33. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/protocol/v2024_11_05.py +0 -0
  34. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/protocol/v2025_03_26.py +0 -0
  35. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/protocol/v2025_06_18.py +0 -0
  36. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/protocol/v2025_11_25.py +0 -0
  37. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/protocol/v2026_07_28.py +0 -0
  38. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/py.typed +0 -0
  39. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/redis.py +0 -0
  40. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/registry.py +0 -0
  41. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/request_state.py +0 -0
  42. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/schema.py +0 -0
  43. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/sessions.py +0 -0
  44. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/skills.py +0 -0
  45. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/specs.py +0 -0
  46. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/sqlite.py +0 -0
  47. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/sse.py +0 -0
  48. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/stdio.py +0 -0
  49. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/stdio_client.py +0 -0
  50. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/subscriptions.py +0 -0
  51. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/tasks.py +0 -0
  52. {aiohttp_tiny_mcp-0.4.0 → aiohttp_tiny_mcp-0.4.1}/src/aiohttp_tiny_mcp/testing.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aiohttp-tiny-mcp
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Remote MCP server and client library for aiohttp
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -173,8 +173,8 @@ Console("/mcp", title="Demo").setup(app, "/console")
173
173
 
174
174
  Open `http://127.0.0.1:8080/console`. It speaks the protocol itself on any of
175
175
  the five revisions, builds a form from each tool's schema, answers the
176
- questions a handler asks, and shows every message either way. Three files from
177
- this package, no build step and no second process.
176
+ questions a handler asks, and shows every message either way. Static files from
177
+ this package need no build step or second process.
178
178
 
179
179
  An MCP host that supports Streamable HTTP can connect to
180
180
  `http://127.0.0.1:8080/mcp`. In an existing aiohttp service, use
@@ -235,7 +235,7 @@ Start with [the documentation overview](https://mosquito.github.io/aiohttp-tiny-
235
235
  2. [Quickstart](https://mosquito.github.io/aiohttp-tiny-mcp/quickstart.html): a complete server, launch command, and client call.
236
236
  3. [How the server fits together](https://mosquito.github.io/aiohttp-tiny-mcp/pieces.html): a conversation across two workers and each object's lifetime.
237
237
  4. [Using Exchange](https://mosquito.github.io/aiohttp-tiny-mcp/guide/exchange.html): request context, progress, questions, and state.
238
- 5. [Authentication](https://mosquito.github.io/aiohttp-tiny-mcp/guide/auth.html): Basic, Bearer, custom subclasses, multiple policies, and permissions.
238
+ 5. [Authentication](https://mosquito.github.io/aiohttp-tiny-mcp/guide/auth.html): Basic, Bearer, GitHub sign-in, custom policies, and permissions.
239
239
  6. [Stores and hubs](https://mosquito.github.io/aiohttp-tiny-mcp/deployment/stores.html): shared backend contracts and deployment requirements.
240
240
  7. [Extensions and skills](https://mosquito.github.io/aiohttp-tiny-mcp/guide/extensions.html): custom methods, skill directories, and resources for older clients.
241
241
 
@@ -131,8 +131,8 @@ Console("/mcp", title="Demo").setup(app, "/console")
131
131
 
132
132
  Open `http://127.0.0.1:8080/console`. It speaks the protocol itself on any of
133
133
  the five revisions, builds a form from each tool's schema, answers the
134
- questions a handler asks, and shows every message either way. Three files from
135
- this package, no build step and no second process.
134
+ questions a handler asks, and shows every message either way. Static files from
135
+ this package need no build step or second process.
136
136
 
137
137
  An MCP host that supports Streamable HTTP can connect to
138
138
  `http://127.0.0.1:8080/mcp`. In an existing aiohttp service, use
@@ -193,7 +193,7 @@ Start with [the documentation overview](https://mosquito.github.io/aiohttp-tiny-
193
193
  2. [Quickstart](https://mosquito.github.io/aiohttp-tiny-mcp/quickstart.html): a complete server, launch command, and client call.
194
194
  3. [How the server fits together](https://mosquito.github.io/aiohttp-tiny-mcp/pieces.html): a conversation across two workers and each object's lifetime.
195
195
  4. [Using Exchange](https://mosquito.github.io/aiohttp-tiny-mcp/guide/exchange.html): request context, progress, questions, and state.
196
- 5. [Authentication](https://mosquito.github.io/aiohttp-tiny-mcp/guide/auth.html): Basic, Bearer, custom subclasses, multiple policies, and permissions.
196
+ 5. [Authentication](https://mosquito.github.io/aiohttp-tiny-mcp/guide/auth.html): Basic, Bearer, GitHub sign-in, custom policies, and permissions.
197
197
  6. [Stores and hubs](https://mosquito.github.io/aiohttp-tiny-mcp/deployment/stores.html): shared backend contracts and deployment requirements.
198
198
  7. [Extensions and skills](https://mosquito.github.io/aiohttp-tiny-mcp/guide/extensions.html): custom methods, skill directories, and resources for older clients.
199
199
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aiohttp-tiny-mcp"
3
- version = "0.4.0"
3
+ version = "0.4.1"
4
4
  description = "Remote MCP server and client library for aiohttp"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aiohttp-tiny-mcp"
3
- version = "0.4.0"
3
+ version = "0.4.1"
4
4
  description = "Remote MCP server and client library for aiohttp"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -17,6 +17,7 @@ FILES = {
17
17
  "": ("index.html", "text/html"),
18
18
  "console.js": ("console.js", "application/javascript"),
19
19
  "console.css": ("console.css", "text/css"),
20
+ "oauth-callback": ("oauth-callback.html", "text/html"),
20
21
  }
21
22
 
22
23
 
@@ -31,12 +32,14 @@ class Console:
31
32
  description: str = "",
32
33
  template: str | Path | None = None,
33
34
  variables: Mapping[str, str] | None = None,
35
+ oauth_client_id: str | None = None,
34
36
  ) -> None:
35
37
  self.endpoint_path = endpoint_path
36
38
  self.title = title
37
39
  self.description = description
38
40
  self.template = Path(template) if template else HERE / "index.html"
39
41
  self.variables = dict(variables or {})
42
+ self.oauth_client_id = oauth_client_id
40
43
 
41
44
  def substitutions(self, base: str) -> dict[str, str]:
42
45
  return {
@@ -44,6 +47,7 @@ class Console:
44
47
  "BASE": base,
45
48
  "TITLE": self.title,
46
49
  "DESCRIPTION": self.description,
50
+ "OAUTH_CLIENT_ID": self.oauth_client_id or "",
47
51
  **self.variables,
48
52
  }
49
53
 
@@ -80,7 +84,7 @@ class Console:
80
84
  )
81
85
 
82
86
  def routes(self, path: str = "/console") -> list[web.RouteDef]:
83
- """The page, either way it is addressed, and its two files."""
87
+ """The page, its assets, and the OAuth callback page."""
84
88
  base = path.rstrip("/")
85
89
  log.debug("console at %s, for the endpoint at %s", base, self.endpoint_path)
86
90
  return [
@@ -89,6 +93,22 @@ class Console:
89
93
  web.get(f"{base}/{{file}}", self.handle),
90
94
  ]
91
95
 
96
+ @staticmethod
97
+ def is_public(request: web.Request) -> bool:
98
+ """Identify a mounted console asset for application authentication middleware.
99
+
100
+ Check the resolved handler, method, and file allowlist. No path prefix
101
+ is trusted, and an unmounted console grants no exemptions.
102
+ """
103
+ handler = request.match_info.handler
104
+ console = getattr(handler, "__self__", None)
105
+ return (
106
+ request.method in {"GET", "HEAD"}
107
+ and isinstance(console, Console)
108
+ and handler == console.handle
109
+ and request.match_info.get("file", "") in FILES
110
+ )
111
+
92
112
  def setup(self, app: web.Application, path: str = "/console") -> web.Application:
93
113
  log.debug("adding the console routes to %r", app)
94
114
  app.add_routes(self.routes(path))
@@ -75,7 +75,7 @@ body {
75
75
  .field.grow > input { flex: 1 1 auto; min-width: 8em; }
76
76
  .field > span { color: var(--ink-soft); font-size: 12px; }
77
77
 
78
- input[type="text"], input[type="number"], select, textarea {
78
+ input[type="text"], input[type="password"], input[type="number"], select, textarea {
79
79
  font: inherit;
80
80
  color: inherit;
81
81
  background: var(--page);
@@ -84,7 +84,7 @@ input[type="text"], input[type="number"], select, textarea {
84
84
  padding: 5px 8px;
85
85
  }
86
86
 
87
- input[type="text"]:focus, select:focus, textarea:focus, input[type="number"]:focus {
87
+ input[type="text"]:focus, input[type="password"]:focus, select:focus, textarea:focus, input[type="number"]:focus {
88
88
  outline: 2px solid var(--accent);
89
89
  outline-offset: -1px;
90
90
  }
@@ -532,3 +532,10 @@ dialog.question #question-text p { margin: 0 0 8px; }
532
532
  dialog.question #question-text :last-child { margin-bottom: 0; }
533
533
  dialog.question menu { display: flex; justify-content: flex-end; gap: 8px; margin: 18px 0 0; padding: 0; }
534
534
  dialog.question .argument { margin-bottom: 10px; }
535
+
536
+ .auth-field { display: flex; flex-direction: column; gap: 4px; margin: 12px 0; }
537
+ .auth-field[hidden] { display: none; }
538
+ .auth-field > input, .auth-field > select { width: 100%; min-width: 0; }
539
+ .auth-endpoint { overflow-wrap: anywhere; font-family: var(--mono); }
540
+ .auth-help { color: var(--ink-soft); font-size: 12px; }
541
+ .auth-error { color: var(--bad); }