aixtools 0.1.10__py3-none-any.whl → 0.1.11__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.

Potentially problematic release.


This version of aixtools might be problematic. Click here for more details.

Files changed (46) hide show
  1. aixtools/_version.py +2 -2
  2. aixtools/mcp/client.py +102 -1
  3. aixtools/testing/aix_test_model.py +2 -0
  4. {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/METADATA +2 -1
  5. {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/RECORD +8 -45
  6. aixtools-0.1.11.dist-info/top_level.txt +1 -0
  7. aixtools-0.1.10.dist-info/top_level.txt +0 -5
  8. docker/mcp-base/Dockerfile +0 -33
  9. docker/mcp-base/zscaler.crt +0 -28
  10. notebooks/example_faulty_mcp_server.ipynb +0 -74
  11. notebooks/example_mcp_server_stdio.ipynb +0 -76
  12. notebooks/example_raw_mcp_client.ipynb +0 -84
  13. notebooks/example_tool_doctor.ipynb +0 -65
  14. scripts/config.sh +0 -28
  15. scripts/lint.sh +0 -32
  16. scripts/log_view.sh +0 -18
  17. scripts/run_example_mcp_server.sh +0 -14
  18. scripts/run_faulty_mcp_server.sh +0 -13
  19. scripts/run_server.sh +0 -29
  20. scripts/test.sh +0 -30
  21. tests/__init__.py +0 -0
  22. tests/unit/__init__.py +0 -0
  23. tests/unit/a2a/__init__.py +0 -0
  24. tests/unit/a2a/google_sdk/__init__.py +0 -0
  25. tests/unit/a2a/google_sdk/pydantic_ai_adapter/__init__.py +0 -0
  26. tests/unit/a2a/google_sdk/pydantic_ai_adapter/test_agent_executor.py +0 -188
  27. tests/unit/a2a/google_sdk/pydantic_ai_adapter/test_storage.py +0 -156
  28. tests/unit/a2a/google_sdk/test_card.py +0 -114
  29. tests/unit/a2a/google_sdk/test_remote_agent_connection.py +0 -413
  30. tests/unit/a2a/google_sdk/test_utils.py +0 -208
  31. tests/unit/agents/__init__.py +0 -0
  32. tests/unit/agents/test_prompt.py +0 -363
  33. tests/unit/compliance/test_private_data.py +0 -329
  34. tests/unit/google/__init__.py +0 -1
  35. tests/unit/google/test_client.py +0 -233
  36. tests/unit/mcp/__init__.py +0 -0
  37. tests/unit/mcp/test_client.py +0 -242
  38. tests/unit/server/__init__.py +0 -0
  39. tests/unit/server/test_path.py +0 -225
  40. tests/unit/server/test_utils.py +0 -362
  41. tests/unit/utils/__init__.py +0 -0
  42. tests/unit/utils/test_files.py +0 -146
  43. tests/unit/vault/__init__.py +0 -0
  44. tests/unit/vault/test_vault.py +0 -246
  45. {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/WHEEL +0 -0
  46. {aixtools-0.1.10.dist-info → aixtools-0.1.11.dist-info}/entry_points.txt +0 -0
aixtools/_version.py CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.1.10'
32
- __version_tuple__ = version_tuple = (0, 1, 10)
31
+ __version__ = version = '0.1.11'
32
+ __version_tuple__ = version_tuple = (0, 1, 11)
33
33
 
34
34
  __commit_id__ = commit_id = None
aixtools/mcp/client.py CHANGED
@@ -1,12 +1,18 @@
1
1
  """MCP server utilities with caching and robust error handling."""
2
2
 
3
3
  import asyncio
4
- from typing import Any
4
+ from contextlib import asynccontextmanager
5
+ from datetime import timedelta
6
+ from typing import Any, AsyncGenerator
5
7
 
6
8
  import anyio
9
+ import httpx
10
+ from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
7
11
  from cachebox import TTLCache
8
12
  from mcp import types as mcp_types
13
+ from mcp.client import streamable_http
9
14
  from mcp.shared.exceptions import McpError
15
+ from mcp.shared.message import SessionMessage
10
16
  from pydantic_ai import RunContext, exceptions
11
17
  from pydantic_ai.mcp import MCPServerStreamableHTTP, ToolResult
12
18
  from pydantic_ai.toolsets.abstract import ToolsetTool
@@ -16,6 +22,7 @@ from aixtools.logging.logging_config import get_logger
16
22
 
17
23
  MCP_TOOL_CACHE_TTL = 300 # 5 minutes
18
24
  DEFAULT_MCP_CONNECTION_TIMEOUT = 30
25
+ DEFAULT_MCP_READ_TIMEOUT = float(60 * 5) # 5 minutes
19
26
  CACHE_KEY = "TOOL_LIST"
20
27
 
21
28
  logger = get_logger(__name__)
@@ -145,6 +152,23 @@ class CachedMCPServerStreamableHTTP(MCPServerStreamableHTTP):
145
152
  logger.warning("MCP %s: %s exception %s: %s", self.url, func.__name__, type(exc), exc)
146
153
  return fallback(exc)
147
154
 
155
+ @property
156
+ def _transport_client(self):
157
+ """Override base transport client with wrapper logging and suppressing exceptions"""
158
+ return patched_streamablehttp_client
159
+
160
+ @asynccontextmanager
161
+ async def client_streams(self):
162
+ """Override base client_streams with wrapper logging and suppressing exceptions"""
163
+ try:
164
+ async with super().client_streams() as streams: # pylint: disable=contextmanager-generator-missing-cleanup
165
+ try:
166
+ yield streams
167
+ except Exception as exc: # pylint: disable=broad-except
168
+ logger.error("MCP %s: client_streams; %s: %s", self.url, type(exc).__name__, exc)
169
+ except Exception as exc: # pylint: disable=broad-except
170
+ logger.error("MCP %s: client_streams: %s: %s", self.url, type(exc).__name__, exc)
171
+
148
172
  async def __aenter__(self):
149
173
  """Enter the context of the cached MCP server with complete cancellation isolation."""
150
174
  async with self._isolation_lock:
@@ -272,3 +296,80 @@ class CachedMCPServerStreamableHTTP(MCPServerStreamableHTTP):
272
296
  raise exceptions.ModelRetry(text)
273
297
 
274
298
  return content[0] if len(content) == 1 else content
299
+
300
+
301
+ class PatchedStreamableHTTPTransport(streamable_http.StreamableHTTPTransport):
302
+ """Patched StreamableHTTPTransport with exception suppression for _handle_post_request."""
303
+
304
+ async def _handle_post_request(self, ctx: streamable_http.RequestContext) -> None:
305
+ """Patched _handle_post_request with proper error handling."""
306
+ try:
307
+ await super()._handle_post_request(ctx)
308
+ except Exception as exc: # pylint: disable=broad-except
309
+ logger.error("MCP %s: _handle_post_request %s: %s", self.url, type(exc).__name__, exc)
310
+
311
+
312
+ @asynccontextmanager
313
+ async def patched_streamablehttp_client( # noqa: PLR0913, pylint: disable=too-many-arguments,too-many-positional-arguments,too-many-locals
314
+ url: str,
315
+ headers: dict[str, str] | None = None,
316
+ timeout: float | timedelta = 30,
317
+ sse_read_timeout: float | timedelta = DEFAULT_MCP_READ_TIMEOUT,
318
+ terminate_on_close: bool = True,
319
+ httpx_client_factory: streamable_http.McpHttpClientFactory = streamable_http.create_mcp_http_client,
320
+ auth: httpx.Auth | None = None,
321
+ ) -> AsyncGenerator[
322
+ tuple[
323
+ MemoryObjectReceiveStream[SessionMessage | Exception],
324
+ MemoryObjectSendStream[SessionMessage],
325
+ streamable_http.GetSessionIdCallback,
326
+ ],
327
+ None,
328
+ ]:
329
+ """Patched version of `streamablehttp_client` with exception suppression."""
330
+ try:
331
+ transport = PatchedStreamableHTTPTransport(url, headers, timeout, sse_read_timeout, auth)
332
+
333
+ read_stream_writer, read_stream = anyio.create_memory_object_stream[SessionMessage | Exception](0)
334
+ write_stream, write_stream_reader = anyio.create_memory_object_stream[SessionMessage](0)
335
+ async with anyio.create_task_group() as tg:
336
+ try:
337
+ async with httpx_client_factory(
338
+ headers=transport.request_headers,
339
+ timeout=httpx.Timeout(transport.timeout, read=transport.sse_read_timeout),
340
+ auth=transport.auth,
341
+ ) as client:
342
+ # Define callbacks that need access to tg
343
+ def start_get_stream() -> None:
344
+ tg.start_soon(transport.handle_get_stream, client, read_stream_writer)
345
+
346
+ tg.start_soon(
347
+ transport.post_writer,
348
+ client,
349
+ write_stream_reader,
350
+ read_stream_writer,
351
+ write_stream,
352
+ start_get_stream,
353
+ tg,
354
+ )
355
+
356
+ try:
357
+ yield (
358
+ read_stream,
359
+ write_stream,
360
+ transport.get_session_id,
361
+ )
362
+ except GeneratorExit:
363
+ logger.warning("patched_streamablehttp_client: GeneratorExit caught, closing streams.")
364
+ finally:
365
+ if transport.session_id and terminate_on_close:
366
+ await transport.terminate_session(client)
367
+ tg.cancel_scope.cancel()
368
+ finally:
369
+ await read_stream_writer.aclose()
370
+ await write_stream.aclose()
371
+ except Exception as exc: # pylint: disable=broad-except
372
+ if str(exc) == "Attempted to exit cancel scope in a different task than it was entered in":
373
+ logger.warning("MCP %s: patched_streamablehttp_client: enter/exit cancel scope task mismatch.", url)
374
+ else:
375
+ logger.error("MCP %s: patched_streamablehttp_client: %s: %s", url, type(exc).__name__, exc)
@@ -108,6 +108,8 @@ class AixTestModel(Model):
108
108
  messages: list[ModelMessage],
109
109
  model_settings: ModelSettings | None,
110
110
  model_request_parameters: ModelRequestParameters,
111
+ *args, # pylint: disable=unused-argument # Accept additional arguments for compatibility with pydantic-ai 1.0.9
112
+ **kwargs, # pylint: disable=unused-argument
111
113
  ) -> AsyncIterator[StreamedResponse]:
112
114
  model_response = await self._request(messages, model_settings, model_request_parameters)
113
115
  yield TestStreamedResponse(_model_name=self.model_name, _structured_response=model_response, _messages=messages)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aixtools
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: Tools for AI exploration and debugging
5
5
  Requires-Python: >=3.11.2
6
6
  Description-Content-Type: text/markdown
@@ -16,6 +16,7 @@ Requires-Dist: langchain-chroma>=0.2.3
16
16
  Requires-Dist: langchain-ollama>=0.3.2
17
17
  Requires-Dist: langchain-openai>=0.3.14
18
18
  Requires-Dist: mcp>=1.11.0
19
+ Requires-Dist: mypy>=1.18.2
19
20
  Requires-Dist: pandas>=2.2.3
20
21
  Requires-Dist: pydantic-ai>=0.4.10
21
22
  Requires-Dist: pylint>=3.3.7
@@ -1,5 +1,5 @@
1
1
  aixtools/__init__.py,sha256=9NGHm7LjsQmsvjTZvw6QFJexSvAU4bCoN_KBk9SCa00,260
2
- aixtools/_version.py,sha256=uf7mpKSLRNNF3RxSXHssYzKadEgmCS7IlRw4lFPAcUg,706
2
+ aixtools/_version.py,sha256=0-Ruc52ECccw_8Ef0d7jMkzrb8fkobUkZLqGGvcm1ik,706
3
3
  aixtools/app.py,sha256=JzQ0nrv_bjDQokllIlGHOV0HEb-V8N6k_nGQH-TEsVU,5227
4
4
  aixtools/chainlit.md,sha256=yC37Ly57vjKyiIvK4oUvf4DYxZCwH7iocTlx7bLeGLU,761
5
5
  aixtools/context.py,sha256=I_MD40ZnvRm5WPKAKqBUAdXIf8YaurkYUUHSVVy-QvU,598
@@ -52,7 +52,7 @@ aixtools/logging/mcp_logger.py,sha256=d2I5l4t0d6rQH17w23FpE1IUD8Ax-mSaKfByCH86q4
52
52
  aixtools/logging/model_patch_logging.py,sha256=MY2EvR7ZSctC4hJxNMe8iACeVayUJ2V5In2GAnKdgOo,2880
53
53
  aixtools/logging/open_telemetry.py,sha256=fJjF1ou_8GyfNfbyWDQPGK6JAUrUaPwURYPHhXEtDBE,1121
54
54
  aixtools/mcp/__init__.py,sha256=tLo2KZ1Ojo-rgEEJBGtZfUw-iOoopWoHDnYQTq3IzfE,163
55
- aixtools/mcp/client.py,sha256=yUcurbNQ8bRaPc8-gK_ESpcPb26d5ckDOEDQrG_YW0c,11823
55
+ aixtools/mcp/client.py,sha256=zN5Na3Vgub2-BoJeldtFrpciBW-TrLjZUpjcQm-biqU,16661
56
56
  aixtools/mcp/example_client.py,sha256=QCFGP3NCNJMOKWjUOnFwjnbJhUSb879IA1ZYmwjRnmc,889
57
57
  aixtools/mcp/example_server.py,sha256=1SWCyrLWsAnOa81HC4QbPJo_lBVu0b3SZBWI-qDh1vQ,458
58
58
  aixtools/mcp/fast_mcp_log.py,sha256=XYOS406dVjn5YTHyGRsRvVNQ0SKlRObfrKj6EeLFjHg,1057
@@ -64,7 +64,7 @@ aixtools/server/path.py,sha256=SaIJxvmhJy3kzx5zJ6d4cKP6kKu2wFFciQkOLGTA4gg,3056
64
64
  aixtools/server/utils.py,sha256=tZWITIx6M-luV9yve4j3rPtYGSSA6zWS0JWEAySne_M,2276
65
65
  aixtools/server/workspace_privacy.py,sha256=grcj82eHSd7gFbb5f_w9nv4TWp50QyU952l0iIPoChM,2375
66
66
  aixtools/testing/__init__.py,sha256=mlmaAR2gmS4SbsYNCxnIprmFpFp-syjgVUkpUszo3mE,166
67
- aixtools/testing/aix_test_model.py,sha256=dlI3sdyvmu4fUs_K4-oazs_a7cE6V-gnI6RQ0_fPVxg,5925
67
+ aixtools/testing/aix_test_model.py,sha256=KDSPwvOOzBVFym14hkXw7BWSLqkFH9nu5OVdfNZoUeQ,6099
68
68
  aixtools/testing/mock_tool.py,sha256=4I0LxxSkLhGIKM2YxCP3cnYI8IYJjdKhfwGZ3dioXsM,2465
69
69
  aixtools/testing/model_patch_cache.py,sha256=238gKC_gSpR3BkeejhetObOkpOR1l2Iz3A6B_eUTRNc,10158
70
70
  aixtools/tools/doctor/__init__.py,sha256=FPwYzC1eJyw8IH0-BP0wgxSprLy6Y_4yXCek7496f2k,64
@@ -81,45 +81,8 @@ aixtools/utils/chainlit/cl_agent_show.py,sha256=vaRuowp4BRvhxEr5hw0zHEJ7iaSF_5bo
81
81
  aixtools/utils/chainlit/cl_utils.py,sha256=fxaxdkcZg6uHdM8uztxdPowg3a2f7VR7B26VPY4t-3c,5738
82
82
  aixtools/vault/__init__.py,sha256=fsr_NuX3GZ9WZ7dGfe0gp_5-z3URxAfwVRXw7Xyc0dU,141
83
83
  aixtools/vault/vault.py,sha256=9dZLWdZQk9qN_Q9Djkofw9LUKnJqnrX5H0fGusVLBhA,6037
84
- docker/mcp-base/Dockerfile,sha256=uislVoTEgRF--AAiyX24sBxlDdfA1ZU5rDM94XYFqvI,1388
85
- docker/mcp-base/zscaler.crt,sha256=fCUNiOfJlWTA7R4zV1Xyb-XC1_nMHPoYTFGvBj1oz6s,1732
86
- notebooks/example_faulty_mcp_server.ipynb,sha256=b2Cy3GXfj-gOBZ7SoUzj25F1rxp5u-32EWPHWQ-sxn8,1729
87
- notebooks/example_mcp_server_stdio.ipynb,sha256=ya4dRKNFU2vQxob-uIhKHGAzINXGQ6MehgKVmSCpHLk,1634
88
- notebooks/example_raw_mcp_client.ipynb,sha256=uchaG-LuuwEpE2oIkmhZ2s1EDb19AgT1fUv2Jxtjgu8,1795
89
- notebooks/example_tool_doctor.ipynb,sha256=bWTlPNI1ZQStwMfr-KSkTGYckJuJmRG_e112Gr4KZ0I,1339
90
- scripts/config.sh,sha256=xnA_S4p2w8fuIEPB4MiTWZdyIlCh5m4XuHY_fhE68kg,820
91
- scripts/lint.sh,sha256=YmPcjfFVe2s-xSaddgSxOsSm9dmHnsmbiLZnuaPgXmY,744
92
- scripts/log_view.sh,sha256=bp8oXFRRbbHpyvHAN85wfDHTVK7vMJOYsBx_-bgECQc,511
93
- scripts/run_example_mcp_server.sh,sha256=f7m7h7O_wo6-nAsYlOXVWIASCOh3Qbuu0XWizlxMhl8,355
94
- scripts/run_faulty_mcp_server.sh,sha256=u_-8NbPDnJQt6IinNSjh8tc2ed-_MjGyipJXrUXaGR8,291
95
- scripts/run_server.sh,sha256=5iiB9bB5M2MuOgxVQqu7Oa_tBVtJpt0uB4z9uLu2J50,720
96
- scripts/test.sh,sha256=KxXWkVqctFRNP8hItJr8K27nDHEkfwNWb1UFhpBQDOk,865
97
- tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
- tests/unit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
99
- tests/unit/a2a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
- tests/unit/a2a/google_sdk/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
101
- tests/unit/a2a/google_sdk/test_card.py,sha256=g8OUIX9BCtApM9y8l_nL1Q7sm3yezxu5yBxrpy76mo4,4359
102
- tests/unit/a2a/google_sdk/test_remote_agent_connection.py,sha256=nIY8eg32w96BAddaQ25mT-lr0ozPb6UrG-_Vpqx5RMY,17492
103
- tests/unit/a2a/google_sdk/test_utils.py,sha256=-eHmIk2GJH57W2bAdTzfRrUUb5jnd9Pf-QSXJogN3g8,8312
104
- tests/unit/a2a/google_sdk/pydantic_ai_adapter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
105
- tests/unit/a2a/google_sdk/pydantic_ai_adapter/test_agent_executor.py,sha256=PcyCw0N3y-txu2KJzufzbCjs7ZfoBBCVjpZuRBqTmOw,7722
106
- tests/unit/a2a/google_sdk/pydantic_ai_adapter/test_storage.py,sha256=tb67pFfvyWSaDfKaiPDNBQfl6-o17WtCMZh3lQHrYxY,5468
107
- tests/unit/agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
108
- tests/unit/agents/test_prompt.py,sha256=YWFZdH_F774hxw79gsWoTWBPVs8UjOAtJOgNXJ8N9gs,15384
109
- tests/unit/compliance/test_private_data.py,sha256=GjH7NCp54Bz1S-CmH_mUe53lb53kllOOJEm448OniRI,13693
110
- tests/unit/google/__init__.py,sha256=eRYHldBi5cFWL7oo2_t5TErI8ESmIjNvBZIcp-w8hSA,45
111
- tests/unit/google/test_client.py,sha256=fXR4Cozea7bdL2prM-1s9IqUQ9AheklQnHpN-4YM3gg,11005
112
- tests/unit/mcp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
113
- tests/unit/mcp/test_client.py,sha256=n9sZvmzNzJfozvxoHweAg4M5ZLNhEizq16IjcZHGdj0,8838
114
- tests/unit/server/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
- tests/unit/server/test_path.py,sha256=1QKiKLLRga9GNxmaUEt_wEZ9U14yzB-7PIhAOgB4wwo,9523
116
- tests/unit/server/test_utils.py,sha256=kvhzdgNfsJl5tqcRBWg2yTR5GPpyrFCOmEIOuHb3904,14848
117
- tests/unit/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
118
- tests/unit/utils/test_files.py,sha256=AKFmXQqXstyKd2PreE4EmQyhQYeqOmu1Sp80MwHrf_Q,5782
119
- tests/unit/vault/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
120
- tests/unit/vault/test_vault.py,sha256=T9V2Opxl3N5sJPftw0Q4lnVOs6urGpAmffe0cz6PUfw,10445
121
- aixtools-0.1.10.dist-info/METADATA,sha256=BvV1AzDpgiy7rjt6AFyUdAiDOwt_mN8CmmEo0JkM4C4,18570
122
- aixtools-0.1.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
123
- aixtools-0.1.10.dist-info/entry_points.txt,sha256=dHoutULEZx7xXSqJrZdViSVjfInJibfLibi2nRXL3SE,56
124
- aixtools-0.1.10.dist-info/top_level.txt,sha256=ee4eF-0pqu45zCUVml0mWIhnXQgqMQper2-49BBVHLY,40
125
- aixtools-0.1.10.dist-info/RECORD,,
84
+ aixtools-0.1.11.dist-info/METADATA,sha256=4mR141qz8BCJbuQy5iTwN0yikrPEKeUb8XPInS5CC6k,18598
85
+ aixtools-0.1.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
86
+ aixtools-0.1.11.dist-info/entry_points.txt,sha256=dHoutULEZx7xXSqJrZdViSVjfInJibfLibi2nRXL3SE,56
87
+ aixtools-0.1.11.dist-info/top_level.txt,sha256=wBn-rw9bCtxrR4AYEYgjilNCUVmKY0LWby9Zan2PRJM,9
88
+ aixtools-0.1.11.dist-info/RECORD,,
@@ -0,0 +1 @@
1
+ aixtools
@@ -1,5 +0,0 @@
1
- aixtools
2
- docker
3
- notebooks
4
- scripts
5
- tests
@@ -1,33 +0,0 @@
1
- FROM ubuntu:22.04
2
-
3
- RUN apt-get -y update && \
4
- apt-get -y install ca-certificates curl gcc git libcap2-bin sudo
5
- RUN mv /usr/bin/sudo /usr/sbin
6
-
7
- # Add Zscaler CA certificate
8
- COPY ./zscaler.crt /usr/local/share/ca-certificates/
9
- RUN update-ca-certificates
10
- ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
11
- ENV CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
12
-
13
- # Install `uv` Python package manager
14
- RUN bash -o pipefail -c "curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh"
15
-
16
- # Add a user matching the sandbox user so that the files and folders created by the MCP server
17
- # are writable by the user in the sandbox containers (UID=1000 must match!)
18
- ENV USER=mcp_user
19
- RUN useradd -m -s /bin/bash -u 1000 ${USER} && \
20
- echo "${USER} ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/${USER} && chmod 0440 /etc/sudoers.d/${USER}
21
- USER ${USER}
22
-
23
- # Build argument: GITHUB_PAT (optional)
24
- # If provided, this GitHub Personal Access Token will be used to authenticate git
25
- # operations against github.com during the build. This is useful for accessing private repositories such as `aixtools`.
26
- # If not set, git will use unauthenticated access (public repositories only).
27
- ARG GITHUB_PAT
28
- RUN if [ -n "$GITHUB_PAT" ]; then \
29
- git config --global url."https://x-access-token:${GITHUB_PAT}@github.com/".insteadOf "https://github.com/"; \
30
- fi
31
-
32
- WORKDIR /app
33
- RUN mkdir data
@@ -1,28 +0,0 @@
1
- -----BEGIN CERTIFICATE-----
2
- MIIE0zCCA7ugAwIBAgIJANu+mC2Jt3uTMA0GCSqGSIb3DQEBCwUAMIGhMQswCQYD
3
- VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIU2FuIEpvc2Ux
4
- FTATBgNVBAoTDFpzY2FsZXIgSW5jLjEVMBMGA1UECxMMWnNjYWxlciBJbmMuMRgw
5
- FgYDVQQDEw9ac2NhbGVyIFJvb3QgQ0ExIjAgBgkqhkiG9w0BCQEWE3N1cHBvcnRA
6
- enNjYWxlci5jb20wHhcNMTQxMjE5MDAyNzU1WhcNNDIwNTA2MDAyNzU1WjCBoTEL
7
- MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAPBgNVBAcTCFNhbiBK
8
- b3NlMRUwEwYDVQQKEwxac2NhbGVyIEluYy4xFTATBgNVBAsTDFpzY2FsZXIgSW5j
9
- LjEYMBYGA1UEAxMPWnNjYWxlciBSb290IENBMSIwIAYJKoZIhvcNAQkBFhNzdXBw
10
- b3J0QHpzY2FsZXIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
11
- qT7STSxZRTgEFFf6doHajSc1vk5jmzmM6BWuOo044EsaTc9eVEV/HjH/1DWzZtcr
12
- fTj+ni205apMTlKBW3UYR+lyLHQ9FoZiDXYXK8poKSV5+Tm0Vls/5Kb8mkhVVqv7
13
- LgYEmvEY7HPY+i1nEGZCa46ZXCOohJ0mBEtB9JVlpDIO+nN0hUMAYYdZ1KZWCMNf
14
- 5J/aTZiShsorN2A38iSOhdd+mcRM4iNL3gsLu99XhKnRqKoHeH83lVdfu1XBeoQz
15
- z5V6gA3kbRvhDwoIlTBeMa5l4yRdJAfdpkbFzqiwSgNdhbxTHnYYorDzKfr2rEFM
16
- dsMU0DHdeAZf711+1CunuQIDAQABo4IBCjCCAQYwHQYDVR0OBBYEFLm33UrNww4M
17
- hp1d3+wcBGnFTpjfMIHWBgNVHSMEgc4wgcuAFLm33UrNww4Mhp1d3+wcBGnFTpjf
18
- oYGnpIGkMIGhMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8G
19
- A1UEBxMIU2FuIEpvc2UxFTATBgNVBAoTDFpzY2FsZXIgSW5jLjEVMBMGA1UECxMM
20
- WnNjYWxlciBJbmMuMRgwFgYDVQQDEw9ac2NhbGVyIFJvb3QgQ0ExIjAgBgkqhkiG
21
- 9w0BCQEWE3N1cHBvcnRAenNjYWxlci5jb22CCQDbvpgtibd7kzAMBgNVHRMEBTAD
22
- AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAw0NdJh8w3NsJu4KHuVZUrmZgIohnTm0j+
23
- RTmYQ9IKA/pvxAcA6K1i/LO+Bt+tCX+C0yxqB8qzuo+4vAzoY5JEBhyhBhf1uK+P
24
- /WVWFZN/+hTgpSbZgzUEnWQG2gOVd24msex+0Sr7hyr9vn6OueH+jj+vCMiAm5+u
25
- kd7lLvJsBu3AO3jGWVLyPkS3i6Gf+rwAp1OsRrv3WnbkYcFf9xjuaf4z0hRCrLN2
26
- xFNjavxrHmsH8jPHVvgc1VD0Opja0l/BRVauTrUaoW6tE+wFG5rEcPGS80jjHK4S
27
- pB5iDj2mUZH1T8lzYtuZy0ZPirxmtsk3135+CKNa2OCAhhFjE0xd
28
- -----END CERTIFICATE-----
@@ -1,74 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "markdown",
5
- "id": "57d36f62",
6
- "metadata": {},
7
- "source": [
8
- "# Example \"Faulty MCP Server\"\n",
9
- "\n",
10
- "Run the server using the script:\n",
11
- "\n",
12
- "```bash\n",
13
- "./scripts/run_faulty_mcp_server.sh\n",
14
- "``` "
15
- ]
16
- },
17
- {
18
- "cell_type": "code",
19
- "execution_count": null,
20
- "id": "ebf6d915",
21
- "metadata": {},
22
- "outputs": [],
23
- "source": [
24
- "from aixtools.agents.agent import get_agent, run_agent\n",
25
- "from pydantic_ai.mcp import MCPServerStreamableHTTP"
26
- ]
27
- },
28
- {
29
- "cell_type": "code",
30
- "execution_count": null,
31
- "id": "97d1e607",
32
- "metadata": {},
33
- "outputs": [],
34
- "source": [
35
- "server = MCPServerStreamableHTTP(\"http://localhost:9999/mcp/\")\n",
36
- "agent = get_agent(mcp_servers=[server])"
37
- ]
38
- },
39
- {
40
- "cell_type": "code",
41
- "execution_count": null,
42
- "id": "fc560d25",
43
- "metadata": {},
44
- "outputs": [],
45
- "source": [
46
- "async with agent:\n",
47
- " # ret = await run_agent(agent, \"What is the add of 40123456789 and 2123456789?\", verbose=True, debug=True)\n",
48
- " # ret = await run_agent(agent, \"Invoke the always_error tool\", verbose=True, debug=True)\n",
49
- " ret = await run_agent(agent, \"Invoke the throw_404_exception tool\", verbose=True, debug=True)"
50
- ]
51
- }
52
- ],
53
- "metadata": {
54
- "kernelspec": {
55
- "display_name": ".venv",
56
- "language": "python",
57
- "name": "python3"
58
- },
59
- "language_info": {
60
- "codemirror_mode": {
61
- "name": "ipython",
62
- "version": 3
63
- },
64
- "file_extension": ".py",
65
- "mimetype": "text/x-python",
66
- "name": "python",
67
- "nbconvert_exporter": "python",
68
- "pygments_lexer": "ipython3",
69
- "version": "3.12.2"
70
- }
71
- },
72
- "nbformat": 4,
73
- "nbformat_minor": 5
74
- }
@@ -1,76 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "markdown",
5
- "id": "57d36f62",
6
- "metadata": {},
7
- "source": [
8
- "# Example MCP Server STDIO"
9
- ]
10
- },
11
- {
12
- "cell_type": "code",
13
- "execution_count": null,
14
- "id": "ebf6d915",
15
- "metadata": {},
16
- "outputs": [],
17
- "source": [
18
- "from aixtools.agents.agent import get_agent, run_agent\n",
19
- "from aixtools.utils.config import PROJECT_DIR\n",
20
- "from pydantic_ai.mcp import MCPServerStdio"
21
- ]
22
- },
23
- {
24
- "cell_type": "code",
25
- "execution_count": null,
26
- "id": "97d1e607",
27
- "metadata": {},
28
- "outputs": [],
29
- "source": [
30
- "mcp_path = PROJECT_DIR /'aixtools' / 'mcp' / 'example_server.py'\n",
31
- "server = MCPServerStdio(command='fastmcp', args=['run', str(mcp_path)])\n",
32
- "agent = get_agent(mcp_servers=[server])"
33
- ]
34
- },
35
- {
36
- "cell_type": "code",
37
- "execution_count": null,
38
- "id": "fc560d25",
39
- "metadata": {},
40
- "outputs": [],
41
- "source": [
42
- "async with agent:\n",
43
- " ret = await run_agent(agent, \"What is the add of 40123456789 and 2123456789?\", verbose=True, debug=True)"
44
- ]
45
- },
46
- {
47
- "cell_type": "code",
48
- "execution_count": null,
49
- "id": "cad32e85",
50
- "metadata": {},
51
- "outputs": [],
52
- "source": []
53
- }
54
- ],
55
- "metadata": {
56
- "kernelspec": {
57
- "display_name": ".venv",
58
- "language": "python",
59
- "name": "python3"
60
- },
61
- "language_info": {
62
- "codemirror_mode": {
63
- "name": "ipython",
64
- "version": 3
65
- },
66
- "file_extension": ".py",
67
- "mimetype": "text/x-python",
68
- "name": "python",
69
- "nbconvert_exporter": "python",
70
- "pygments_lexer": "ipython3",
71
- "version": "3.12.2"
72
- }
73
- },
74
- "nbformat": 4,
75
- "nbformat_minor": 5
76
- }
@@ -1,84 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "markdown",
5
- "id": "57d36f62",
6
- "metadata": {},
7
- "source": [
8
- "# Example \"Raw MCP Client\"\n",
9
- "\n",
10
- "Run the server using the script:\n",
11
- "\n",
12
- "```bash\n",
13
- "./scripts/run_faulty_mcp_server.sh\n",
14
- "``` "
15
- ]
16
- },
17
- {
18
- "cell_type": "code",
19
- "execution_count": null,
20
- "id": "cad32e85",
21
- "metadata": {},
22
- "outputs": [],
23
- "source": [
24
- "from fastmcp import Client\n",
25
- "import rich\n",
26
- "\n",
27
- "client = Client(\"http://localhost:9999/mcp/\")"
28
- ]
29
- },
30
- {
31
- "cell_type": "code",
32
- "execution_count": null,
33
- "id": "e372fc6a",
34
- "metadata": {},
35
- "outputs": [],
36
- "source": [
37
- "async with client:\n",
38
- " # Basic server interaction\n",
39
- " await client.ping()\n",
40
- " \n",
41
- " # # List available operations\n",
42
- " # tools = await client.list_tools()\n",
43
- " # rich.print(tools)\n",
44
- " # \n",
45
- " # # Execute 'add' tool\n",
46
- " # result = await client.call_tool(\"add\", {\"a\": 7, \"b\": 3})\n",
47
- " # rich.print(result)\n",
48
- "\n",
49
- " # Execute 'add' tool\n",
50
- " result = await client.call_tool(\"throw_404_exception\", {})\n",
51
- " rich.print(result)\n"
52
- ]
53
- },
54
- {
55
- "cell_type": "code",
56
- "execution_count": null,
57
- "id": "a8a743e2",
58
- "metadata": {},
59
- "outputs": [],
60
- "source": []
61
- }
62
- ],
63
- "metadata": {
64
- "kernelspec": {
65
- "display_name": ".venv",
66
- "language": "python",
67
- "name": "python3"
68
- },
69
- "language_info": {
70
- "codemirror_mode": {
71
- "name": "ipython",
72
- "version": 3
73
- },
74
- "file_extension": ".py",
75
- "mimetype": "text/x-python",
76
- "name": "python",
77
- "nbconvert_exporter": "python",
78
- "pygments_lexer": "ipython3",
79
- "version": "3.12.2"
80
- }
81
- },
82
- "nbformat": 4,
83
- "nbformat_minor": 5
84
- }
@@ -1,65 +0,0 @@
1
- {
2
- "cells": [
3
- {
4
- "cell_type": "markdown",
5
- "id": "dab47237",
6
- "metadata": {},
7
- "source": [
8
- "# Tool doctor example"
9
- ]
10
- },
11
- {
12
- "cell_type": "code",
13
- "execution_count": null,
14
- "id": "9735e38c",
15
- "metadata": {},
16
- "outputs": [],
17
- "source": [
18
- "# Example 1: A reasonably well-defined tool\n",
19
- "from aixtools.tools.doctor import tool_doctor\n",
20
- "\n",
21
- "\n",
22
- "def add(a: int, b: int) -> int:\n",
23
- " \"\"\" Add two numbers \"\"\"\n",
24
- " return a + b\n",
25
- "\n",
26
- "# Example 2: A poorly defined tool\n",
27
- "def z(a: int, b: int) -> int:\n",
28
- " \"\"\" performs some arithmentic with two parameters \"\"\"\n",
29
- " return a + b\n"
30
- ]
31
- },
32
- {
33
- "cell_type": "code",
34
- "execution_count": null,
35
- "id": "e50d48d6",
36
- "metadata": {},
37
- "outputs": [],
38
- "source": [
39
- "# Call tool doctor\n",
40
- "ret = await tool_doctor([add, z])"
41
- ]
42
- }
43
- ],
44
- "metadata": {
45
- "kernelspec": {
46
- "display_name": ".venv",
47
- "language": "python",
48
- "name": "python3"
49
- },
50
- "language_info": {
51
- "codemirror_mode": {
52
- "name": "ipython",
53
- "version": 3
54
- },
55
- "file_extension": ".py",
56
- "mimetype": "text/x-python",
57
- "name": "python",
58
- "nbconvert_exporter": "python",
59
- "pygments_lexer": "ipython3",
60
- "version": "3.12.2"
61
- }
62
- },
63
- "nbformat": 4,
64
- "nbformat_minor": 5
65
- }
scripts/config.sh DELETED
@@ -1,28 +0,0 @@
1
- #-----------------------------------------------------------------------------
2
- #
3
- # This template script sets up the environment for the project by defining the
4
- # project directory and activating the virtual environment.
5
- #
6
- #-----------------------------------------------------------------------------
7
-
8
- export SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
9
-
10
- # Project directory
11
- export PROJECT_DIR="$( cd $SCRIPTS_DIR/.. && pwd -P )"
12
- export PROJECT_NAME="$(basename $PROJECT_DIR)"
13
-
14
- # Data directories
15
- export DATA_DIR="$PROJECT_DIR/data"
16
- export LOGS_DIR="$PROJECT_DIR/logs"
17
- export PG_DATA_DIR="$DATA_DIR/data/db/postgres"
18
-
19
- # Server configuration
20
- export PORT=8081
21
-
22
- # Activate virtual environment
23
- if [ "${OS-}" == "Windows_NT" ]; then
24
- source .venv/Scripts/activate
25
- else
26
- source .venv/bin/activate
27
- fi
28
-