Title: Mounting a Streamable HTTP MCP endpoint on existing FastAPI app does not work · Issue #1367 · modelcontextprotocol/python-sdk · GitHub
Open Graph Title: Mounting a Streamable HTTP MCP endpoint on existing FastAPI app does not work · Issue #1367 · modelcontextprotocol/python-sdk
X Title: Mounting a Streamable HTTP MCP endpoint on existing FastAPI app does not work · Issue #1367 · modelcontextprotocol/python-sdk
Description: Initial Checks I confirm that I'm using the latest version of MCP Python SDK I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue Description Hi, We are trying to c...
Open Graph Description: Initial Checks I confirm that I'm using the latest version of MCP Python SDK I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this ...
X Description: Initial Checks I confirm that I'm using the latest version of MCP Python SDK I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening t...
Opengraph URL: https://github.com/modelcontextprotocol/python-sdk/issues/1367
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Mounting a Streamable HTTP MCP endpoint on existing FastAPI app does not work","articleBody":"### Initial Checks\n\n- [x] I confirm that I'm using the latest version of MCP Python SDK\n- [x] I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue\n\n### Description\n\nHi,\n\nWe are trying to create a web server with 2 endpoints:\n\n- `/mcp` : the MCP server endpoint\n- `/hello` : whatever custom endpoint getting JSON returning JSON\n\nThis is important because it allows to build more advanced app than just a MCP server, and avoid having 35 micro services to manage.\n\nWe use a really popular solution for doing so: FastAPI, which claims full support for mounting ASGI apps, such as the `Starlette` object returned by `mcp.streamable_http_app()`\n\n\n\n```python\nfrom fastapi import FastAPI\nfrom mcp.server.fastmcp import FastMCP\n\napp = FastAPI(title=\"Hello MCP\")\n\n\nmcp = FastMCP(\n \"SIB BioData MCP\",\n debug=True,\n dependencies=[\"mcp\"],\n)\n\n@mcp.tool()\nasync def just_for_test(question: str) -\u003e str:\n \"\"\"Nothing special\n\n Args:\n question: The question to be answered\n\n Returns:\n The question\n \"\"\"\n return question\n\nmcp_app = mcp.streamable_http_app()\napp.mount(\"/mcp\", mcp_app)\n\n@app.post(\"/hello\")\nasync def chat():\n print(\"hello\")\n```\n\nRun with:\n\n```sh\nuv run uvicorn main:app --port 8000\n```\n\nGoing directly to http://localhost:8000/mcp gives plain text `Not Found`\n\nGoing to any actually not defined path gives the usual FastAPI `{\"detail\":\"Not Found\"}`\n\nSo this shows something has been mounted on `/mcp`, but your`Starlette` object returns an incorrect error (it can't be not found, maximum it could be method not allowed, or something else, but not found does not seems correct here)\n\n\nTry to access it with the official MCP client using the official documentation:\n\n```python\nimport asyncio\nfrom mcp import ClientSession\nfrom mcp.client.streamable_http import streamablehttp_client\n\nasync def main():\n mcp_url = \"http://localhost:8000/mcp\"\n async with streamablehttp_client(mcp_url) as (read_stream, write_stream, _):\n async with ClientSession(read_stream, write_stream) as session:\n await session.initialize()\n tools = await session.list_tools()\n print(f\"Available tools: {[tool.name for tool in tools.tools]}\")\n\nif __name__ == \"__main__\":\n asyncio.run(main())\n```\n\n\nWe get a redirect and a 404 in the server logs:\n\n```\nINFO: 192.168.97.1:49048 - \"POST /mcp HTTP/1.1\" 307 Temporary Redirect\nINFO: 192.168.97.1:49048 - \"POST /mcp/ HTTP/1.1\" 404 Not Found\n```\n\nSo now if we change the mcp_url to http://localhost:8000/mcp/mcp we get:\n\n```\n File \"/app/.venv/lib/python3.12/site-packages/mcp/server/streamable_http_manager.py\", line 138, in handle_request\n raise RuntimeError(\"Task group is not initialized. Make sure to use run().\")\nRuntimeError: Task group is not initialized. Make sure to use run().\n```\n\n\n## Many problems here\n\n- Not sure how I should use run here, since I am deploying this with uvicorn? \n- On your side, having the `Starlette` already preconfigured to mount the endpoint on `/mcp` does not seems like a good pattern. From our (devs using your lib) pov, mounting on `/` is problematic, we should be able to easily mount the MCP endpoint on any path no? Or is there somewhere in the protocol specified that the Streamable HTTP endpoints absolutely needs to be mounted on `/mcp`? Not sure exactly of your lib internals, but I should be able to deploy multiple MCP endpoints on different path on the same server\n\n\nStrangely we had less issues implementing the [same thing in rust](https://github.com/sib-swiss/sparql-mcp/blob/main/src/lib.rs#L154) with axum and the official rmcp crate. And it seems like the rmcp crate let us mount the MCP endpoint on any path, so we should be able to do the same with python\n\n\nNote that deploying the exact same MCP app directly with `mcp.run(transport=\"streamable-http\")` works fine (the client scripts above works and print the tools)\n\nWould it be possible to clarify a bit how can this be done properly? A basic working example is the usual way of documenting such feature (it's just 10 lines)\n\nThanks a lot\n\n### Example Code\n\n```Python\nSee above for the multiple code snippets\n```\n\n### Python \u0026 MCP Python SDK\n\n```Text\npython 3.12\nmcp[cli] \u003e=1.14.0\n```","author":{"url":"https://github.com/vemonet","@type":"Person","name":"vemonet"},"datePublished":"2025-09-15T11:38:00.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":4},"url":"https://github.com/1367/python-sdk/issues/1367"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:9a787820-ab3b-0e2e-d2fc-5b05f1a8837f |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | EA48:1C1873:6704C0:8C6B4A:6A62DD6E |
| html-safe-nonce | 02f8e6d0d1fbb6ac60715bba64861eb19360d2ef7a9b1e02ebefc0041e9f7306 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFQTQ4OjFDMTg3Mzo2NzA0QzA6OEM2QjRBOjZBNjJERDZFIiwidmlzaXRvcl9pZCI6IjI2NDE0NDc4MTcwMjI5ODc2MzAiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | f2f58fceea3b4695141a329de8b1d31607ead7070676a9124c4459f2d096a06d |
| hovercard-subject-tag | issue:3417569834 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/modelcontextprotocol/python-sdk/1367/issue_layout |
| twitter:image | https://opengraph.githubassets.com/ec06ad361772a9300667fae3825abd6cc5492ca52d237292d923cec9844d895e/modelcontextprotocol/python-sdk/issues/1367 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/ec06ad361772a9300667fae3825abd6cc5492ca52d237292d923cec9844d895e/modelcontextprotocol/python-sdk/issues/1367 |
| og:image:alt | Initial Checks I confirm that I'm using the latest version of MCP Python SDK I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this ... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | vemonet |
| hostname | github.com |
| expected-hostname | github.com |
| None | df33b1b61ee7b9a0af988199bfc3503c9c1acafb1f1d40e1f140ea7c84f890dd |
| turbo-cache-control | no-preview |
| go-import | github.com/modelcontextprotocol/python-sdk git https://github.com/modelcontextprotocol/python-sdk.git |
| octolytics-dimension-user_id | 182288589 |
| octolytics-dimension-user_login | modelcontextprotocol |
| octolytics-dimension-repository_id | 862584018 |
| octolytics-dimension-repository_nwo | modelcontextprotocol/python-sdk |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 862584018 |
| octolytics-dimension-repository_network_root_nwo | modelcontextprotocol/python-sdk |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | d41cd1bdb290013455c0ac430fa755621733f5eb |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width