diff --git a/nocobase_crm_mcp/server.py b/nocobase_crm_mcp/server.py index cf16b00..af27c17 100644 --- a/nocobase_crm_mcp/server.py +++ b/nocobase_crm_mcp/server.py @@ -641,10 +641,14 @@ def _read_token_from_env(env_name: str) -> str: def create_http_app(server: Any, token: str, upload_endpoint: UploadEndpoint | None = None) -> Any: if upload_endpoint is None: return BearerTokenAuthMiddleware(server.streamable_http_app(), token) + + async def upload_route(request: Any) -> Any: + return await upload_endpoint(request) + mcp_app = server.streamable_http_app() app = Starlette( routes=[ - Route("/uploads", endpoint=upload_endpoint, methods=["POST"]), + Route("/uploads", endpoint=upload_route, methods=["POST"]), Mount("/", app=mcp_app), ], lifespan=mcp_app.router.lifespan_context, diff --git a/tests/test_server.py b/tests/test_server.py index d7cd24a..b932db4 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -292,6 +292,23 @@ class ServerTests(unittest.TestCase): self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {"uploaded": True}) + def test_upload_route_dispatches_callable_endpoint_objects_as_request_handlers(self) -> None: + if FastMCP is None: + self.skipTest("MCP SDK is not installed") + + server = create_server(crm_service=FakeCrmService(), readonly=True) + app = create_http_app(server, "secret", upload_endpoint=FakeUploadEndpoint()) + + async def request_upload() -> httpx.Response: + async with httpx.AsyncClient( + transport=httpx.ASGITransport(app=app), base_url="http://testserver" + ) as client: + return await client.post("/uploads", headers={"Authorization": "Bearer secret"}) + + response = asyncio.run(request_upload()) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), {"uploaded": True}) + def test_upload_route_preserves_mcp_application_lifespan(self) -> None: lifecycle = {"started": False, "stopped": False}