onetool-mcp 1.0.0b1__py3-none-any.whl → 1.0.0rc2__py3-none-any.whl

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 (81) hide show
  1. onetool/cli.py +63 -4
  2. onetool_mcp-1.0.0rc2.dist-info/METADATA +266 -0
  3. onetool_mcp-1.0.0rc2.dist-info/RECORD +129 -0
  4. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/licenses/LICENSE.txt +1 -1
  5. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/licenses/NOTICE.txt +54 -64
  6. ot/__main__.py +6 -6
  7. ot/config/__init__.py +48 -46
  8. ot/config/global_templates/__init__.py +2 -2
  9. ot/config/{defaults → global_templates}/diagram-templates/api-flow.mmd +33 -33
  10. ot/config/{defaults → global_templates}/diagram-templates/c4-context.puml +30 -30
  11. ot/config/{defaults → global_templates}/diagram-templates/class-diagram.mmd +87 -87
  12. ot/config/{defaults → global_templates}/diagram-templates/feature-mindmap.mmd +70 -70
  13. ot/config/{defaults → global_templates}/diagram-templates/microservices.d2 +81 -81
  14. ot/config/{defaults → global_templates}/diagram-templates/project-gantt.mmd +37 -37
  15. ot/config/{defaults → global_templates}/diagram-templates/state-machine.mmd +42 -42
  16. ot/config/global_templates/diagram.yaml +167 -0
  17. ot/config/global_templates/onetool.yaml +3 -1
  18. ot/config/{defaults → global_templates}/prompts.yaml +102 -97
  19. ot/config/global_templates/security.yaml +31 -0
  20. ot/config/global_templates/servers.yaml +93 -12
  21. ot/config/global_templates/snippets.yaml +5 -26
  22. ot/config/{defaults → global_templates}/tool_templates/__init__.py +7 -7
  23. ot/config/loader.py +221 -105
  24. ot/config/mcp.py +5 -1
  25. ot/config/secrets.py +192 -190
  26. ot/decorators.py +116 -116
  27. ot/executor/__init__.py +35 -35
  28. ot/executor/base.py +16 -16
  29. ot/executor/fence_processor.py +83 -83
  30. ot/executor/linter.py +142 -142
  31. ot/executor/pep723.py +288 -288
  32. ot/executor/runner.py +20 -6
  33. ot/executor/simple.py +163 -163
  34. ot/executor/validator.py +603 -164
  35. ot/http_client.py +145 -145
  36. ot/logging/__init__.py +37 -37
  37. ot/logging/entry.py +213 -213
  38. ot/logging/format.py +191 -188
  39. ot/logging/span.py +349 -349
  40. ot/meta.py +236 -14
  41. ot/paths.py +32 -49
  42. ot/prompts.py +218 -218
  43. ot/proxy/manager.py +14 -2
  44. ot/registry/__init__.py +189 -189
  45. ot/registry/parser.py +269 -269
  46. ot/server.py +330 -315
  47. ot/shortcuts/__init__.py +15 -15
  48. ot/shortcuts/aliases.py +87 -87
  49. ot/shortcuts/snippets.py +258 -258
  50. ot/stats/__init__.py +35 -35
  51. ot/stats/html.py +2 -2
  52. ot/stats/reader.py +354 -354
  53. ot/stats/timing.py +57 -57
  54. ot/support.py +63 -63
  55. ot/tools.py +1 -1
  56. ot/utils/batch.py +161 -161
  57. ot/utils/cache.py +120 -120
  58. ot/utils/exceptions.py +23 -23
  59. ot/utils/factory.py +178 -179
  60. ot/utils/format.py +65 -65
  61. ot/utils/http.py +202 -202
  62. ot/utils/platform.py +45 -45
  63. ot/utils/truncate.py +69 -69
  64. ot_tools/__init__.py +4 -4
  65. ot_tools/_convert/__init__.py +12 -12
  66. ot_tools/_convert/pdf.py +254 -254
  67. ot_tools/diagram.yaml +167 -167
  68. ot_tools/scaffold.py +2 -2
  69. ot_tools/transform.py +124 -19
  70. ot_tools/web_fetch.py +94 -43
  71. onetool_mcp-1.0.0b1.dist-info/METADATA +0 -163
  72. onetool_mcp-1.0.0b1.dist-info/RECORD +0 -132
  73. ot/config/defaults/bench.yaml +0 -4
  74. ot/config/defaults/onetool.yaml +0 -25
  75. ot/config/defaults/servers.yaml +0 -7
  76. ot/config/defaults/snippets.yaml +0 -4
  77. ot_tools/firecrawl.py +0 -732
  78. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/WHEEL +0 -0
  79. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/entry_points.txt +0 -0
  80. /ot/config/{defaults → global_templates}/tool_templates/extension.py +0 -0
  81. /ot/config/{defaults → global_templates}/tool_templates/isolated.py +0 -0
ot/http_client.py CHANGED
@@ -1,145 +1,145 @@
1
- """Shared HTTP client utilities.
2
-
3
- Provides a unified http_get() function for making HTTP GET requests with:
4
- - Consistent error handling and message format
5
- - Optional headers (for auth tokens)
6
- - Optional timeout (defaults from config)
7
- - Optional LogSpan integration for observability
8
- - Content-type aware response parsing (JSON or text)
9
- - Connection pooling via shared client singleton
10
-
11
- Usage:
12
- from ot.http_client import http_get
13
-
14
- # Basic GET
15
- success, result = http_get("https://api.example.com/data")
16
-
17
- # With headers and params
18
- success, result = http_get(
19
- "https://api.example.com/search",
20
- params={"q": "test"},
21
- headers={"Authorization": "Bearer token"},
22
- )
23
-
24
- # With LogSpan for observability
25
- success, result = http_get(
26
- url,
27
- log_span="api.fetch",
28
- log_data={"query": query},
29
- )
30
- """
31
-
32
- from __future__ import annotations
33
-
34
- import atexit
35
- import contextlib
36
- import threading
37
- from typing import Any
38
-
39
- import httpx
40
-
41
- # Global shared HTTP client with connection pooling
42
- _client: httpx.Client | None = None
43
- _client_lock = threading.Lock()
44
-
45
-
46
- def _get_shared_client() -> httpx.Client:
47
- """Get or create the shared HTTP client with connection pooling."""
48
- global _client
49
- if _client is None:
50
- with _client_lock:
51
- if _client is None:
52
- _client = httpx.Client(
53
- timeout=30.0,
54
- limits=httpx.Limits(
55
- max_keepalive_connections=20,
56
- max_connections=100,
57
- keepalive_expiry=30.0,
58
- ),
59
- )
60
- atexit.register(_shutdown_client)
61
- return _client
62
-
63
-
64
- def _shutdown_client() -> None:
65
- """Close the shared client on exit."""
66
- global _client
67
- if _client is not None:
68
- with contextlib.suppress(Exception):
69
- _client.close()
70
- _client = None
71
-
72
-
73
- def http_get(
74
- url: str,
75
- *,
76
- params: dict[str, Any] | None = None,
77
- headers: dict[str, str] | None = None,
78
- timeout: float | None = None,
79
- log_span: str | None = None,
80
- log_data: dict[str, Any] | None = None,
81
- ) -> tuple[bool, dict[str, Any] | str]:
82
- """Make HTTP GET request with unified error handling.
83
-
84
- Args:
85
- url: Full URL to request
86
- params: Optional query parameters
87
- headers: Optional HTTP headers (e.g., auth tokens)
88
- timeout: Request timeout in seconds (defaults to 30.0)
89
- log_span: Optional LogSpan name for observability
90
- log_data: Optional data to include in LogSpan
91
-
92
- Returns:
93
- Tuple of (success, result). If success, result is parsed JSON dict
94
- or response text. If failure, result is error message string.
95
- """
96
- from ot.logging import LogSpan as LogSpanClass
97
-
98
- # Default timeout
99
- if timeout is None:
100
- timeout = 30.0
101
-
102
- # Optional LogSpan wrapper
103
- span: LogSpanClass | None = None
104
- if log_span:
105
- span = LogSpanClass(span=log_span, **(log_data or {}))
106
- span.__enter__()
107
-
108
- try:
109
- client = _get_shared_client()
110
- response = client.get(url, params=params, headers=headers, timeout=timeout)
111
- response.raise_for_status()
112
-
113
- # Parse based on content type
114
- content_type = response.headers.get("content-type", "")
115
- if "application/json" in content_type:
116
- result = response.json()
117
- else:
118
- result = response.text
119
-
120
- if span:
121
- span.add("status", response.status_code)
122
-
123
- return True, result
124
-
125
- except httpx.HTTPStatusError as e:
126
- error_msg = f"HTTP error ({e.response.status_code}): {e.response.text[:200]}"
127
- if span:
128
- span.add("error", f"HTTP {e.response.status_code}")
129
- return False, error_msg
130
-
131
- except httpx.RequestError as e:
132
- error_msg = f"Request failed: {e}"
133
- if span:
134
- span.add("error", str(e))
135
- return False, error_msg
136
-
137
- except Exception as e:
138
- error_msg = f"Error: {e}"
139
- if span:
140
- span.add("error", str(e))
141
- return False, error_msg
142
-
143
- finally:
144
- if span:
145
- span.__exit__(None, None, None)
1
+ """Shared HTTP client utilities.
2
+
3
+ Provides a unified http_get() function for making HTTP GET requests with:
4
+ - Consistent error handling and message format
5
+ - Optional headers (for auth tokens)
6
+ - Optional timeout (defaults from config)
7
+ - Optional LogSpan integration for observability
8
+ - Content-type aware response parsing (JSON or text)
9
+ - Connection pooling via shared client singleton
10
+
11
+ Usage:
12
+ from ot.http_client import http_get
13
+
14
+ # Basic GET
15
+ success, result = http_get("https://api.example.com/data")
16
+
17
+ # With headers and params
18
+ success, result = http_get(
19
+ "https://api.example.com/search",
20
+ params={"q": "test"},
21
+ headers={"Authorization": "Bearer token"},
22
+ )
23
+
24
+ # With LogSpan for observability
25
+ success, result = http_get(
26
+ url,
27
+ log_span="api.fetch",
28
+ log_data={"query": query},
29
+ )
30
+ """
31
+
32
+ from __future__ import annotations
33
+
34
+ import atexit
35
+ import contextlib
36
+ import threading
37
+ from typing import Any
38
+
39
+ import httpx
40
+
41
+ # Global shared HTTP client with connection pooling
42
+ _client: httpx.Client | None = None
43
+ _client_lock = threading.Lock()
44
+
45
+
46
+ def _get_shared_client() -> httpx.Client:
47
+ """Get or create the shared HTTP client with connection pooling."""
48
+ global _client
49
+ if _client is None:
50
+ with _client_lock:
51
+ if _client is None:
52
+ _client = httpx.Client(
53
+ timeout=30.0,
54
+ limits=httpx.Limits(
55
+ max_keepalive_connections=20,
56
+ max_connections=100,
57
+ keepalive_expiry=30.0,
58
+ ),
59
+ )
60
+ atexit.register(_shutdown_client)
61
+ return _client
62
+
63
+
64
+ def _shutdown_client() -> None:
65
+ """Close the shared client on exit."""
66
+ global _client
67
+ if _client is not None:
68
+ with contextlib.suppress(Exception):
69
+ _client.close()
70
+ _client = None
71
+
72
+
73
+ def http_get(
74
+ url: str,
75
+ *,
76
+ params: dict[str, Any] | None = None,
77
+ headers: dict[str, str] | None = None,
78
+ timeout: float | None = None,
79
+ log_span: str | None = None,
80
+ log_data: dict[str, Any] | None = None,
81
+ ) -> tuple[bool, dict[str, Any] | str]:
82
+ """Make HTTP GET request with unified error handling.
83
+
84
+ Args:
85
+ url: Full URL to request
86
+ params: Optional query parameters
87
+ headers: Optional HTTP headers (e.g., auth tokens)
88
+ timeout: Request timeout in seconds (defaults to 30.0)
89
+ log_span: Optional LogSpan name for observability
90
+ log_data: Optional data to include in LogSpan
91
+
92
+ Returns:
93
+ Tuple of (success, result). If success, result is parsed JSON dict
94
+ or response text. If failure, result is error message string.
95
+ """
96
+ from ot.logging import LogSpan as LogSpanClass
97
+
98
+ # Default timeout
99
+ if timeout is None:
100
+ timeout = 30.0
101
+
102
+ # Optional LogSpan wrapper
103
+ span: LogSpanClass | None = None
104
+ if log_span:
105
+ span = LogSpanClass(span=log_span, **(log_data or {}))
106
+ span.__enter__()
107
+
108
+ try:
109
+ client = _get_shared_client()
110
+ response = client.get(url, params=params, headers=headers, timeout=timeout)
111
+ response.raise_for_status()
112
+
113
+ # Parse based on content type
114
+ content_type = response.headers.get("content-type", "")
115
+ if "application/json" in content_type:
116
+ result = response.json()
117
+ else:
118
+ result = response.text
119
+
120
+ if span:
121
+ span.add("status", response.status_code)
122
+
123
+ return True, result
124
+
125
+ except httpx.HTTPStatusError as e:
126
+ error_msg = f"HTTP error ({e.response.status_code}): {e.response.text[:200]}"
127
+ if span:
128
+ span.add("error", f"HTTP {e.response.status_code}")
129
+ return False, error_msg
130
+
131
+ except httpx.RequestError as e:
132
+ error_msg = f"Request failed: {e}"
133
+ if span:
134
+ span.add("error", str(e))
135
+ return False, error_msg
136
+
137
+ except Exception as e:
138
+ error_msg = f"Error: {e}"
139
+ if span:
140
+ span.add("error", str(e))
141
+ return False, error_msg
142
+
143
+ finally:
144
+ if span:
145
+ span.__exit__(None, None, None)
ot/logging/__init__.py CHANGED
@@ -1,37 +1,37 @@
1
- """Structured logging for OneTool MCP server.
2
-
3
- Provides JSON-structured logging with:
4
- - LogEntry: Fluent API for building log entries with auto-timing
5
- - LogSpan: Context manager for auto-logging operations
6
- - File-only JSON output
7
- """
8
-
9
- from loguru import logger
10
-
11
- # Remove Loguru's default console handler immediately.
12
- # This prevents logs from appearing on console before configure_logging() is called.
13
- logger.remove()
14
-
15
- from ot.logging.config import ( # noqa: E402
16
- configure_logging,
17
- configure_test_logging,
18
- )
19
- from ot.logging.entry import LogEntry # noqa: E402
20
- from ot.logging.format import ( # noqa: E402
21
- format_log_entry,
22
- format_value,
23
- sanitize_for_output,
24
- sanitize_url,
25
- )
26
- from ot.logging.span import LogSpan # noqa: E402
27
-
28
- __all__ = [
29
- "LogEntry",
30
- "LogSpan",
31
- "configure_logging",
32
- "configure_test_logging",
33
- "format_log_entry",
34
- "format_value",
35
- "sanitize_for_output",
36
- "sanitize_url",
37
- ]
1
+ """Structured logging for OneTool MCP server.
2
+
3
+ Provides JSON-structured logging with:
4
+ - LogEntry: Fluent API for building log entries with auto-timing
5
+ - LogSpan: Context manager for auto-logging operations
6
+ - File-only JSON output
7
+ """
8
+
9
+ from loguru import logger
10
+
11
+ # Remove Loguru's default console handler immediately.
12
+ # This prevents logs from appearing on console before configure_logging() is called.
13
+ logger.remove()
14
+
15
+ from ot.logging.config import ( # noqa: E402
16
+ configure_logging,
17
+ configure_test_logging,
18
+ )
19
+ from ot.logging.entry import LogEntry # noqa: E402
20
+ from ot.logging.format import ( # noqa: E402
21
+ format_log_entry,
22
+ format_value,
23
+ sanitize_for_output,
24
+ sanitize_url,
25
+ )
26
+ from ot.logging.span import LogSpan # noqa: E402
27
+
28
+ __all__ = [
29
+ "LogEntry",
30
+ "LogSpan",
31
+ "configure_logging",
32
+ "configure_test_logging",
33
+ "format_log_entry",
34
+ "format_value",
35
+ "sanitize_for_output",
36
+ "sanitize_url",
37
+ ]