acp-sdk 0.0.1__tar.gz → 0.0.4__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 (149) hide show
  1. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/PKG-INFO +2 -2
  2. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/clients/simple-chatbot/mcp_simple_chatbot/main.py +2 -3
  3. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/highlevel/agents.py +4 -4
  4. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/pyproject.toml +11 -21
  5. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/agents/base.py +1 -3
  6. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/agents/templates.py +1 -3
  7. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/context.py +3 -3
  8. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/server.py +8 -7
  9. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/lowlevel/server.py +36 -25
  10. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/shared/memory.py +3 -3
  11. acp_sdk-0.0.4/tasks.toml +67 -0
  12. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/issues/test_100_tool_listing.py +3 -3
  13. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/issues/test_152_resource_mime_type.py +30 -30
  14. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/issues/test_176_progress_token.py +3 -3
  15. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/test_server.py +0 -1
  16. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/shared/test_session.py +1 -0
  17. acp_sdk-0.0.1/examples/servers/simple-tool/.python-version +0 -1
  18. acp_sdk-0.0.1/uv.lock +0 -786
  19. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  20. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  21. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/.github/workflows/check-lock.yml +0 -0
  22. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/.github/workflows/main-checks.yml +0 -0
  23. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/.github/workflows/publish-pypi.yml +0 -0
  24. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/.github/workflows/pull-request-checks.yml +0 -0
  25. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/.github/workflows/shared.yml +0 -0
  26. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/.gitignore +0 -0
  27. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/.pre-commit-config.yaml +0 -0
  28. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/CLAUDE.md +0 -0
  29. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/CODE_OF_CONDUCT.md +0 -0
  30. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/CONTRIBUTING.md +0 -0
  31. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/LICENSE +0 -0
  32. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/README.md +0 -0
  33. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/RELEASE.md +0 -0
  34. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/SECURITY.md +0 -0
  35. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/README.md +0 -0
  36. {acp_sdk-0.0.1 → acp_sdk-0.0.4/examples/clients/simple-chatbot}/.python-version +0 -0
  37. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/clients/simple-chatbot/README.MD +0 -0
  38. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/clients/simple-chatbot/mcp_simple_chatbot/.env.example +0 -0
  39. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/clients/simple-chatbot/mcp_simple_chatbot/requirements.txt +0 -0
  40. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/clients/simple-chatbot/mcp_simple_chatbot/servers_config.json +0 -0
  41. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/clients/simple-chatbot/mcp_simple_chatbot/test.db +0 -0
  42. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/clients/simple-chatbot/pyproject.toml +0 -0
  43. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/clients/simple-chatbot/uv.lock +0 -0
  44. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/highlevel/complex_inputs.py +0 -0
  45. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/highlevel/desktop.py +0 -0
  46. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/highlevel/echo.py +0 -0
  47. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/highlevel/memory.py +0 -0
  48. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/highlevel/parameter_descriptions.py +0 -0
  49. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/highlevel/readme-quickstart.py +0 -0
  50. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/highlevel/screenshot.py +0 -0
  51. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/highlevel/simple_echo.py +0 -0
  52. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/highlevel/text_me.py +0 -0
  53. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/highlevel/unicode_example.py +0 -0
  54. {acp_sdk-0.0.1/examples/clients/simple-chatbot → acp_sdk-0.0.4/examples/servers/simple-prompt}/.python-version +0 -0
  55. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-prompt/README.md +0 -0
  56. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-prompt/mcp_simple_prompt/__init__.py +0 -0
  57. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-prompt/mcp_simple_prompt/__main__.py +0 -0
  58. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-prompt/mcp_simple_prompt/server.py +0 -0
  59. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-prompt/pyproject.toml +0 -0
  60. {acp_sdk-0.0.1/examples/servers/simple-prompt → acp_sdk-0.0.4/examples/servers/simple-resource}/.python-version +0 -0
  61. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-resource/README.md +0 -0
  62. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-resource/mcp_simple_resource/__init__.py +0 -0
  63. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-resource/mcp_simple_resource/__main__.py +0 -0
  64. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-resource/mcp_simple_resource/server.py +0 -0
  65. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-resource/pyproject.toml +0 -0
  66. {acp_sdk-0.0.1/examples/servers/simple-resource → acp_sdk-0.0.4/examples/servers/simple-tool}/.python-version +0 -0
  67. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-tool/README.md +0 -0
  68. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-tool/mcp_simple_tool/__init__.py +0 -0
  69. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-tool/mcp_simple_tool/__main__.py +0 -0
  70. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-tool/mcp_simple_tool/server.py +0 -0
  71. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/examples/servers/simple-tool/pyproject.toml +0 -0
  72. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/__init__.py +0 -0
  73. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/cli/__init__.py +0 -0
  74. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/cli/claude.py +0 -0
  75. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/cli/cli.py +0 -0
  76. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/client/__init__.py +0 -0
  77. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/client/__main__.py +0 -0
  78. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/client/session.py +0 -0
  79. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/client/sse.py +0 -0
  80. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/client/stdio.py +0 -0
  81. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/py.typed +0 -0
  82. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/__init__.py +0 -0
  83. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/__main__.py +0 -0
  84. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/__init__.py +0 -0
  85. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/agents/__init__.py +0 -0
  86. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/agents/agent_manager.py +0 -0
  87. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/exceptions.py +0 -0
  88. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/prompts/__init__.py +0 -0
  89. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/prompts/base.py +0 -0
  90. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/prompts/manager.py +0 -0
  91. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/prompts/prompt_manager.py +0 -0
  92. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/resources/__init__.py +0 -0
  93. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/resources/base.py +0 -0
  94. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/resources/resource_manager.py +0 -0
  95. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/resources/templates.py +0 -0
  96. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/resources/types.py +0 -0
  97. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/tools/__init__.py +0 -0
  98. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/tools/base.py +0 -0
  99. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/tools/tool_manager.py +0 -0
  100. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/utilities/__init__.py +0 -0
  101. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/utilities/func_metadata.py +0 -0
  102. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/utilities/logging.py +0 -0
  103. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/highlevel/utilities/types.py +0 -0
  104. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/lowlevel/__init__.py +0 -0
  105. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/lowlevel/helper_types.py +0 -0
  106. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/models.py +0 -0
  107. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/session.py +0 -0
  108. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/sse.py +0 -0
  109. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/stdio.py +0 -0
  110. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/server/websocket.py +0 -0
  111. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/shared/__init__.py +0 -0
  112. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/shared/context.py +0 -0
  113. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/shared/exceptions.py +0 -0
  114. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/shared/progress.py +0 -0
  115. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/shared/session.py +0 -0
  116. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/shared/version.py +0 -0
  117. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/src/acp/types.py +0 -0
  118. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/__init__.py +0 -0
  119. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/client/__init__.py +0 -0
  120. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/client/test_config.py +0 -0
  121. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/client/test_session.py +0 -0
  122. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/client/test_stdio.py +0 -0
  123. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/conftest.py +0 -0
  124. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/issues/test_129_resource_templates.py +0 -0
  125. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/issues/test_141_resource_templates.py +0 -0
  126. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/issues/test_88_random_error.py +0 -0
  127. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/__init__.py +0 -0
  128. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/__init__.py +0 -0
  129. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/prompts/__init__.py +0 -0
  130. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/prompts/test_base.py +0 -0
  131. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/prompts/test_manager.py +0 -0
  132. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/resources/__init__.py +0 -0
  133. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/resources/test_file_resources.py +0 -0
  134. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/resources/test_function_resources.py +0 -0
  135. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/resources/test_resource_manager.py +0 -0
  136. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/resources/test_resource_template.py +0 -0
  137. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/resources/test_resources.py +0 -0
  138. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/servers/__init__.py +0 -0
  139. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/servers/test_file_server.py +0 -0
  140. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/test_func_metadata.py +0 -0
  141. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/test_parameter_descriptions.py +0 -0
  142. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/fastmcp/test_tool_manager.py +0 -0
  143. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/test_read_resource.py +0 -0
  144. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/test_session.py +0 -0
  145. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/server/test_stdio.py +0 -0
  146. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/shared/test_memory.py +0 -0
  147. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/shared/test_sse.py +0 -0
  148. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/test_examples.py +0 -0
  149. {acp_sdk-0.0.1 → acp_sdk-0.0.4}/tests/test_types.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: acp-sdk
3
- Version: 0.0.1
3
+ Version: 0.0.4
4
4
  Summary: Agent Communication Protocol SDK
5
5
  Project-URL: Homepage, https://github.com/i-am-bee/beeai
6
6
  Project-URL: Repository, https://github.com/i-am-bee/beeai
@@ -17,7 +17,7 @@ Classifier: Programming Language :: Python :: 3.10
17
17
  Classifier: Programming Language :: Python :: 3.11
18
18
  Classifier: Programming Language :: Python :: 3.12
19
19
  Classifier: Programming Language :: Python :: 3.13
20
- Requires-Python: >=3.10
20
+ Requires-Python: <4.0,>=3.10
21
21
  Requires-Dist: anyio>=4.5
22
22
  Requires-Dist: httpx-sse>=0.4
23
23
  Requires-Dist: httpx>=0.27
@@ -7,9 +7,9 @@ from contextlib import AsyncExitStack
7
7
  from typing import Any
8
8
 
9
9
  import httpx
10
+ from acp import ClientSession, StdioServerParameters
10
11
  from acp.client.stdio import stdio_client
11
12
  from dotenv import load_dotenv
12
- from mcp import ClientSession, StdioServerParameters
13
13
 
14
14
  # Configure logging
15
15
  logging.basicConfig(
@@ -322,8 +322,7 @@ class ChatSession:
322
322
  total = result["total"]
323
323
  percentage = (progress / total) * 100
324
324
  logging.info(
325
- f"Progress: {progress}/{total} "
326
- f"({percentage:.1f}%)"
325
+ f"Progress: {progress}/{total} ({percentage:.1f}%)"
327
326
  )
328
327
 
329
328
  return f"Tool execution result: {result}"
@@ -6,16 +6,16 @@ from acp.server.highlevel import Context, Server
6
6
  class Input(BaseModel):
7
7
  prompt: str
8
8
 
9
+
9
10
  class Output(BaseModel):
10
11
  text: str
11
12
 
13
+
12
14
  acp_server = Server()
13
15
 
16
+
14
17
  @acp_server.agent(
15
- name="Echoagent",
16
- description="Echoing agent",
17
- input=Input,
18
- output=Output
18
+ name="Echoagent", description="Echoing agent", input=Input, output=Output
19
19
  )
20
20
  async def run_agent(input: Input, ctx: Context) -> Output:
21
21
  agent = "Echoagent"
@@ -1,9 +1,9 @@
1
1
  [project]
2
2
  name = "acp-sdk"
3
- version = "0.0.1"
3
+ version = "0.0.4"
4
4
  description = "Agent Communication Protocol SDK"
5
5
  readme = "README.md"
6
- requires-python = ">=3.10"
6
+ requires-python = ">=3.10,<4.0"
7
7
  authors = [{ name = "IBM Corp." }, { name = "Anthropic, PBC" }]
8
8
  maintainers = []
9
9
  keywords = ["git", "acp", "llm"]
@@ -31,16 +31,8 @@ dependencies = [
31
31
  "setuptools==75.8.0",
32
32
  ]
33
33
 
34
- [project.optional-dependencies]
35
- rich = ["rich>=13.9.4"]
36
- cli = ["typer>=0.12.4", "python-dotenv>=1.0.0"]
37
-
38
- [project.scripts]
39
- acp = "acp.cli:app [cli]"
40
-
41
- [tool.uv]
42
- resolution = "lowest-direct"
43
- dev-dependencies = [
34
+ [dependency-groups]
35
+ dev = [
44
36
  "pyright>=1.1.391",
45
37
  "pytest>=8.3.4",
46
38
  "ruff>=0.8.5",
@@ -49,6 +41,13 @@ dev-dependencies = [
49
41
  "pytest-xdist>=3.6.1",
50
42
  ]
51
43
 
44
+ [project.optional-dependencies]
45
+ rich = ["rich>=13.9.4"]
46
+ cli = ["typer>=0.12.4", "python-dotenv>=1.0.0"]
47
+
48
+ [project.scripts]
49
+ acp = "acp.cli:app [cli]"
50
+
52
51
  [build-system]
53
52
  requires = ["hatchling"]
54
53
  build-backend = "hatchling.build"
@@ -63,8 +62,6 @@ packages = ["src/acp"]
63
62
 
64
63
  [tool.pyright]
65
64
  include = ["src/acp"]
66
- venvPath = "."
67
- venv = ".venv"
68
65
 
69
66
  [tool.ruff.lint]
70
67
  select = ["E", "F", "I"]
@@ -77,10 +74,3 @@ target-version = "py310"
77
74
  [tool.ruff.lint.per-file-ignores]
78
75
  "__init__.py" = ["F401"]
79
76
  "tests/server/fastmcp/test_func_metadata.py" = ["E501"]
80
-
81
-
82
- [tool.uv.workspace]
83
- members = ["examples/servers/*"]
84
-
85
- [tool.uv.sources]
86
- acp = { workspace = true }
@@ -14,9 +14,7 @@ class Agent(BaseModel):
14
14
  input: Type[BaseModel] = Field(description="Model for input")
15
15
  output: Type[BaseModel] = Field(description="Model for output")
16
16
 
17
- run_fn: Callable[[BaseModel, "Context"], Awaitable[BaseModel]] = Field(
18
- exclude=True
19
- )
17
+ run_fn: Callable[[BaseModel, "Context"], Awaitable[BaseModel]] = Field(exclude=True)
20
18
  destroy_fn: Callable[["Context"], Awaitable[None]] | None = Field(exclude=True)
21
19
 
22
20
  model_config = ConfigDict(extra="allow")
@@ -16,8 +16,6 @@ class AgentTemplate(BaseModel):
16
16
  input: Type[BaseModel] = Field(description="Model for run input")
17
17
  output: Type[BaseModel] = Field(description="Model for run output")
18
18
 
19
- create_fn: Callable[[BaseModel, "Context"], Awaitable[Agent]] = Field(
20
- exclude=True
21
- )
19
+ create_fn: Callable[[BaseModel, "Context"], Awaitable[Agent]] = Field(exclude=True)
22
20
 
23
21
  model_config = ConfigDict(extra="allow")
@@ -124,9 +124,9 @@ class Context(BaseModel):
124
124
  Returns:
125
125
  The resource content as either text or bytes
126
126
  """
127
- assert (
128
- self._fastmcp is not None
129
- ), "Context is not available outside of a request"
127
+ assert self._fastmcp is not None, (
128
+ "Context is not available outside of a request"
129
+ )
130
130
  return await self._fastmcp.read_resource(uri)
131
131
 
132
132
  async def log(
@@ -467,7 +467,7 @@ class Server:
467
467
  config: Type[BaseModel],
468
468
  input: Type[BaseModel],
469
469
  output: Type[BaseModel],
470
- **kwargs
470
+ **kwargs,
471
471
  ) -> Callable:
472
472
  """Decorator to register an agent template.
473
473
 
@@ -494,7 +494,7 @@ class Server:
494
494
  input=input,
495
495
  output=output,
496
496
  create_fn=func,
497
- **kwargs
497
+ **kwargs,
498
498
  )
499
499
  self.add_agent_template(template)
500
500
  return func
@@ -513,7 +513,7 @@ class Server:
513
513
  configSchema=template.config.model_json_schema(),
514
514
  inputSchema=template.input.model_json_schema(),
515
515
  outputSchema=template.output.model_json_schema(),
516
- **(template.model_extra if template.model_extra else {})
516
+ **(template.model_extra if template.model_extra else {}),
517
517
  )
518
518
  for template in templates
519
519
  ]
@@ -529,7 +529,7 @@ class Server:
529
529
  description: str,
530
530
  input: Type[BaseModel],
531
531
  output: Type[BaseModel],
532
- **kwargs
532
+ **kwargs,
533
533
  ) -> Callable:
534
534
  """Decorator to register an agent.
535
535
 
@@ -554,7 +554,7 @@ class Server:
554
554
  output=output,
555
555
  run_fn=func,
556
556
  destroy_fn=None,
557
- **kwargs
557
+ **kwargs,
558
558
  )
559
559
  self.add_agent(agent=agent)
560
560
  return func
@@ -570,7 +570,7 @@ class Server:
570
570
  description=agent.description,
571
571
  inputSchema=agent.input.model_json_schema(),
572
572
  outputSchema=agent.output.model_json_schema(),
573
- **(agent.model_extra if agent.model_extra else {})
573
+ **(agent.model_extra if agent.model_extra else {}),
574
574
  )
575
575
  for agent in agents
576
576
  ]
@@ -613,7 +613,7 @@ class Server:
613
613
  self._mcp_server.create_initialization_options(),
614
614
  )
615
615
 
616
- async def run_sse_async(self) -> None:
616
+ async def run_sse_async(self, **uvicorn_kwargs) -> None:
617
617
  """Run the server using SSE transport."""
618
618
  from starlette.applications import Starlette
619
619
  from starlette.routing import Mount, Route
@@ -643,6 +643,7 @@ class Server:
643
643
  host=self.settings.host,
644
644
  port=self.settings.port,
645
645
  log_level=self.settings.log_level.lower(),
646
+ **uvicorn_kwargs,
646
647
  )
647
648
  server = uvicorn.Server(config)
648
649
  await server.serve()
@@ -68,8 +68,10 @@ import contextvars
68
68
  import logging
69
69
  import warnings
70
70
  from collections.abc import Awaitable, Callable
71
+ from contextlib import AsyncExitStack
71
72
  from typing import Any, Sequence
72
73
 
74
+ import anyio
73
75
  from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
74
76
  from pydantic import AnyUrl
75
77
 
@@ -182,7 +184,7 @@ class Server:
182
184
  if types.ListAgentsRequest in self.request_handlers:
183
185
  agents_capability = types.AgentsCapability(
184
186
  templates=types.ListAgentTemplatesRequest in self.request_handlers,
185
- listChanged=notification_options.agents_changed
187
+ listChanged=notification_options.agents_changed,
186
188
  )
187
189
 
188
190
  # Set logging capabilities if handler exists
@@ -538,30 +540,41 @@ class Server:
538
540
  # in-process servers.
539
541
  raise_exceptions: bool = False,
540
542
  ):
541
- with warnings.catch_warnings(record=True) as w:
542
- async with ServerSession(
543
- read_stream, write_stream, initialization_options
544
- ) as session:
543
+ async with AsyncExitStack() as stack:
544
+ session = await stack.enter_async_context(
545
+ ServerSession(read_stream, write_stream, initialization_options)
546
+ )
547
+
548
+ async with anyio.create_task_group() as tg:
545
549
  async for message in session.incoming_messages:
546
550
  logger.debug(f"Received message: {message}")
547
551
 
548
- match message:
549
- case (
550
- RequestResponder(
551
- request=types.ClientRequest(root=req)
552
- ) as responder
553
- ):
554
- with responder:
555
- await self._handle_request(
556
- message, req, session, raise_exceptions
557
- )
558
- case types.ClientNotification(root=notify):
559
- await self._handle_notification(notify)
560
-
561
- for warning in w:
562
- logger.info(
563
- f"Warning: {warning.category.__name__}: {warning.message}"
552
+ tg.start_soon(
553
+ self._handle_message, message, session, raise_exceptions
554
+ )
555
+
556
+ async def _handle_message(
557
+ self,
558
+ message: RequestResponder[types.ClientRequest, types.ServerResult]
559
+ | types.ClientNotification
560
+ | Exception,
561
+ session: ServerSession,
562
+ raise_exceptions: bool = False,
563
+ ):
564
+ with warnings.catch_warnings(record=True) as w:
565
+ match message:
566
+ case (
567
+ RequestResponder(request=types.ClientRequest(root=req)) as responder
568
+ ):
569
+ with responder:
570
+ await self._handle_request(
571
+ message, req, session, raise_exceptions
564
572
  )
573
+ case types.ClientNotification(root=notify):
574
+ await self._handle_notification(notify)
575
+
576
+ for warning in w:
577
+ logger.info(f"Warning: {warning.category.__name__}: {warning.message}")
565
578
 
566
579
  async def _handle_request(
567
580
  self,
@@ -614,14 +627,12 @@ class Server:
614
627
  assert type(notify) in self.notification_handlers
615
628
 
616
629
  handler = self.notification_handlers[type(notify)]
617
- logger.debug(
618
- f"Dispatching notification of type " f"{type(notify).__name__}"
619
- )
630
+ logger.debug(f"Dispatching notification of type {type(notify).__name__}")
620
631
 
621
632
  try:
622
633
  await handler(notify)
623
634
  except Exception as err:
624
- logger.error(f"Uncaught exception in notification handler: " f"{err}")
635
+ logger.error(f"Uncaught exception in notification handler: {err}")
625
636
 
626
637
 
627
638
  async def _ping_handler(request: types.PingRequest) -> types.ServerResult:
@@ -20,9 +20,9 @@ MessageStream = tuple[
20
20
 
21
21
 
22
22
  @asynccontextmanager
23
- async def create_client_server_memory_streams() -> (
24
- AsyncGenerator[tuple[MessageStream, MessageStream], None]
25
- ):
23
+ async def create_client_server_memory_streams() -> AsyncGenerator[
24
+ tuple[MessageStream, MessageStream], None
25
+ ]:
26
26
  """
27
27
  Creates a pair of bidirectional memory streams for client-server communication.
28
28
 
@@ -0,0 +1,67 @@
1
+ # check
2
+
3
+ ["acp-python-sdk:check"]
4
+ depends = ["acp-python-sdk:check:*"]
5
+
6
+ ["acp-python-sdk:check:ruff-check"]
7
+ depends = ["setup:uv"]
8
+ dir = "{{config_root}}/packages/acp-python-sdk"
9
+ run = "uv run ruff check --quiet"
10
+ sources = ["src/**/*.py"]
11
+ outputs = { auto = true }
12
+
13
+ ["acp-python-sdk:check:ruff-format"]
14
+ depends = ["setup:uv"]
15
+ dir = "{{config_root}}/packages/acp-python-sdk"
16
+ run = "uv run ruff format --quiet --check"
17
+ sources = ["src/**/*.py"]
18
+ outputs = { auto = true }
19
+
20
+ ["acp-python-sdk:check:pyright"]
21
+ depends = ["setup:uv"]
22
+ dir = "{{config_root}}/packages/acp-python-sdk"
23
+ run = "uv run pyright"
24
+ sources = ["src/**/*.py"]
25
+ outputs = { auto = true }
26
+
27
+ # fix
28
+
29
+ ["acp-python-sdk:fix"]
30
+ depends = ["acp-python-sdk:fix:*"]
31
+
32
+ ["acp-python-sdk:fix:ruff-check"]
33
+ depends = ["setup:uv"]
34
+ dir = "{{config_root}}/packages/acp-python-sdk"
35
+ run = "uv run ruff check --quiet --fix"
36
+ sources = ["src/**/*.py"]
37
+ outputs = { auto = true }
38
+
39
+ ["acp-python-sdk:fix:ruff-format"]
40
+ depends = ["setup:uv"]
41
+ dir = "{{config_root}}/packages/acp-python-sdk"
42
+ run = "uv run ruff format --quiet"
43
+ sources = ["src/**/*.py"]
44
+ outputs = { auto = true }
45
+
46
+ # test
47
+
48
+ ["acp-python-sdk:test"]
49
+ depends = ["setup:uv"]
50
+ dir = "{{config_root}}/packages/acp-python-sdk"
51
+ run = "uv run pytest"
52
+ sources = ["src/**/*.py"]
53
+ outputs = { auto = true }
54
+
55
+ # build
56
+
57
+ ["acp-python-sdk:build"]
58
+ dir = "{{config_root}}/packages/acp-python-sdk"
59
+ run = "uv build --out-dir dist"
60
+ sources = ["src/**/*.py"]
61
+ outputs = ["dist/**/*"]
62
+
63
+ # clean
64
+
65
+ ["acp-python-sdk:clean"]
66
+ dir = "{{config_root}}/packages/acp-python-sdk"
67
+ run = "rm -rf dist"
@@ -30,6 +30,6 @@ async def test_list_tools_returns_all_tools():
30
30
  # Verify each tool is unique and has the correct name
31
31
  tool_names = [tool.name for tool in tools]
32
32
  expected_names = [f"tool_{i}" for i in range(num_tools)]
33
- assert sorted(tool_names) == sorted(
34
- expected_names
35
- ), "Tool names don't match expected names"
33
+ assert sorted(tool_names) == sorted(expected_names), (
34
+ "Tool names don't match expected names"
35
+ )
@@ -45,31 +45,31 @@ async def test_fastmcp_resource_mime_type():
45
45
  bytes_resource = mapping["test://image_bytes"]
46
46
 
47
47
  # Verify mime types
48
- assert (
49
- string_resource.mimeType == "image/png"
50
- ), "String resource mime type not respected"
51
- assert (
52
- bytes_resource.mimeType == "image/png"
53
- ), "Bytes resource mime type not respected"
48
+ assert string_resource.mimeType == "image/png", (
49
+ "String resource mime type not respected"
50
+ )
51
+ assert bytes_resource.mimeType == "image/png", (
52
+ "Bytes resource mime type not respected"
53
+ )
54
54
 
55
55
  # Also verify the content can be read correctly
56
56
  string_result = await client.read_resource(AnyUrl("test://image"))
57
57
  assert len(string_result.contents) == 1
58
- assert (
59
- getattr(string_result.contents[0], "text") == base64_string
60
- ), "Base64 string mismatch"
61
- assert (
62
- string_result.contents[0].mimeType == "image/png"
63
- ), "String content mime type not preserved"
58
+ assert getattr(string_result.contents[0], "text") == base64_string, (
59
+ "Base64 string mismatch"
60
+ )
61
+ assert string_result.contents[0].mimeType == "image/png", (
62
+ "String content mime type not preserved"
63
+ )
64
64
 
65
65
  bytes_result = await client.read_resource(AnyUrl("test://image_bytes"))
66
66
  assert len(bytes_result.contents) == 1
67
67
  assert (
68
68
  base64.b64decode(getattr(bytes_result.contents[0], "blob")) == image_bytes
69
69
  ), "Bytes mismatch"
70
- assert (
71
- bytes_result.contents[0].mimeType == "image/png"
72
- ), "Bytes content mime type not preserved"
70
+ assert bytes_result.contents[0].mimeType == "image/png", (
71
+ "Bytes content mime type not preserved"
72
+ )
73
73
 
74
74
 
75
75
  async def test_lowlevel_resource_mime_type():
@@ -119,28 +119,28 @@ async def test_lowlevel_resource_mime_type():
119
119
  bytes_resource = mapping["test://image_bytes"]
120
120
 
121
121
  # Verify mime types
122
- assert (
123
- string_resource.mimeType == "image/png"
124
- ), "String resource mime type not respected"
125
- assert (
126
- bytes_resource.mimeType == "image/png"
127
- ), "Bytes resource mime type not respected"
122
+ assert string_resource.mimeType == "image/png", (
123
+ "String resource mime type not respected"
124
+ )
125
+ assert bytes_resource.mimeType == "image/png", (
126
+ "Bytes resource mime type not respected"
127
+ )
128
128
 
129
129
  # Also verify the content can be read correctly
130
130
  string_result = await client.read_resource(AnyUrl("test://image"))
131
131
  assert len(string_result.contents) == 1
132
- assert (
133
- getattr(string_result.contents[0], "text") == base64_string
134
- ), "Base64 string mismatch"
135
- assert (
136
- string_result.contents[0].mimeType == "image/png"
137
- ), "String content mime type not preserved"
132
+ assert getattr(string_result.contents[0], "text") == base64_string, (
133
+ "Base64 string mismatch"
134
+ )
135
+ assert string_result.contents[0].mimeType == "image/png", (
136
+ "String content mime type not preserved"
137
+ )
138
138
 
139
139
  bytes_result = await client.read_resource(AnyUrl("test://image_bytes"))
140
140
  assert len(bytes_result.contents) == 1
141
141
  assert (
142
142
  base64.b64decode(getattr(bytes_result.contents[0], "blob")) == image_bytes
143
143
  ), "Bytes mismatch"
144
- assert (
145
- bytes_result.contents[0].mimeType == "image/png"
146
- ), "Bytes content mime type not preserved"
144
+ assert bytes_result.contents[0].mimeType == "image/png", (
145
+ "Bytes content mime type not preserved"
146
+ )
@@ -32,9 +32,9 @@ async def test_progress_token_zero_first_call():
32
32
  await ctx.report_progress(10, 10) # Complete
33
33
 
34
34
  # Verify progress notifications
35
- assert (
36
- mock_session.send_progress_notification.call_count == 3
37
- ), "All progress notifications should be sent"
35
+ assert mock_session.send_progress_notification.call_count == 3, (
36
+ "All progress notifications should be sent"
37
+ )
38
38
  mock_session.send_progress_notification.assert_any_call(
39
39
  progress_token=0, progress=0.0, total=10.0
40
40
  )
@@ -520,7 +520,6 @@ class TestContextInjection:
520
520
  async def test_context_logging(self):
521
521
  from unittest.mock import patch
522
522
 
523
-
524
523
  """Test that context logging methods work."""
525
524
  mcp = Server()
526
525
 
@@ -44,6 +44,7 @@ async def test_in_flight_requests_cleared_after_completion(
44
44
 
45
45
 
46
46
  @pytest.mark.anyio
47
+ @pytest.mark.skip("broken on Python 3.11+, needs investigation")
47
48
  async def test_request_cancellation():
48
49
  """Test that requests can be cancelled while in-flight."""
49
50
  # The tool is already registered in the fixture