Title: Pass entire request object to handlers; add raw request to MCP base Request · Issue #195 · modelcontextprotocol/python-sdk · GitHub
Open Graph Title: Pass entire request object to handlers; add raw request to MCP base Request · Issue #195 · modelcontextprotocol/python-sdk
X Title: Pass entire request object to handlers; add raw request to MCP base Request · Issue #195 · modelcontextprotocol/python-sdk
Description: Is your feature request related to a problem? Please describe. I have an MCP server that sits in front of my API to allow LLMs to interact with it. My API requires an authorization header. I have hacked a way to do this in my fork, but e...
Open Graph Description: Is your feature request related to a problem? Please describe. I have an MCP server that sits in front of my API to allow LLMs to interact with it. My API requires an authorization header. I have h...
X Description: Is your feature request related to a problem? Please describe. I have an MCP server that sits in front of my API to allow LLMs to interact with it. My API requires an authorization header. I have h...
Opengraph URL: https://github.com/modelcontextprotocol/python-sdk/issues/195
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Pass entire request object to handlers; add raw request to MCP base Request","articleBody":"**Is your feature request related to a problem? Please describe.**\nI have an MCP server that sits in front of my API to allow LLMs to interact with it. My API requires an authorization header.\n\nI have hacked a way to do this in my fork, but essentially the MCP client is able to pass through headers. Only need to use this for the `/sse` request. Currently, the handlers extract the arguments they need in the decorator. We could instead add a field to the base Request class called `raw_request` or `headers` if we just need that and then ensure this is added to the request object before passing it to the handler.\n\n**Describe the solution you'd like**\n```python\n# src/mcp/types.py\nclass Request(BaseModel, Generic[RequestParamsT, MethodT]):\n \"\"\"Base class for JSON-RPC requests.\"\"\"\n\n method: MethodT\n params: RequestParamsT\n headers: dict[str, Any] | None = None # \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n model_config = ConfigDict(extra=\"allow\")\n\n---------------------\n# src/mcp/server/fastmcp/server.py\n def call_tool(self):\n def decorator(\n func: Callable[\n ...,\n Awaitable[\n Sequence[\n types.TextContent | types.ImageContent | types.EmbeddedResource\n ]\n ],\n ],\n ):\n logger.debug(\"Registering handler for CallToolRequest\")\n\n async def handler(req: types.CallToolRequest):\n try:\n results = await func(req) # \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n return types.ServerResult(\n types.CallToolResult(content=list(results), isError=False)\n )\n except Exception as e:\n return types.ServerResult(\n types.CallToolResult(\n content=[types.TextContent(type=\"text\", text=str(e))],\n isError=True,\n )\n )\n\n self.request_handlers[types.CallToolRequest] = handler\n return func\n\n return decorator\n\n-----------------------------\n# src/mcp/server/fastmcp/server.py\n async def run_sse_async(self, middleware: list[type] = []) -\u003e None:\n \"\"\"Run the server using SSE transport.\"\"\"\n from starlette.applications import Starlette\n from starlette.routing import Mount, Route\n\n sse = SseServerTransport(\"/messages/\")\n\n async def handle_sse(request):\n async with sse.connect_sse(\n request.scope, request.receive, request._send\n ) as streams:\n await self._mcp_server.run(\n streams[0],\n streams[1],\n self._mcp_server.create_initialization_options(),\n raw_request=request, # \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n )\n\n starlette_app = Starlette(\n debug=self.settings.debug,\n routes=[\n Route(\"/sse\", endpoint=handle_sse),\n Mount(\"/messages/\", app=sse.handle_post_message),\n ],\n )\n\n config = uvicorn.Config(\n starlette_app,\n host=self.settings.host,\n port=self.settings.port,\n log_level=self.settings.log_level.lower(),\n )\n server = uvicorn.Server(config)\n await server.serve()\n\n---------------------------\n# src/mcp/server/lowlevel/server.py\n async def run(\n self,\n read_stream: MemoryObjectReceiveStream[types.JSONRPCMessage | Exception],\n write_stream: MemoryObjectSendStream[types.JSONRPCMessage],\n initialization_options: InitializationOptions,\n raw_request: Any | None = None, # \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n # When False, exceptions are returned as messages to the client.\n # When True, exceptions are raised, which will cause the server to shut down\n # but also make tracing exceptions much easier during testing and when using\n # in-process servers.\n raise_exceptions: bool = False,\n ):\n with warnings.catch_warnings(record=True) as w:\n async with ServerSession(\n read_stream, write_stream, initialization_options\n ) as session:\n async for message in session.incoming_messages:\n logger.debug(f\"Received message: {message}\")\n\n match message:\n case (\n RequestResponder(\n request=types.ClientRequest(root=req)\n ) as responder\n ):\n with responder:\n if raw_request is not None:\n req.headers = raw_request.headers # \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n await self._handle_request(\n message, req, session, raise_exceptions\n )\n case types.ClientNotification(root=notify):\n await self._handle_notification(notify)\n\n for warning in w:\n logger.info(\n f\"Warning: {warning.category.__name__}: {warning.message}\"\n )\n```\n\nand then use this like:\n\n```python\n# already supported on client\ntransport = await exit_stack.enter_async_context(\n sse_client(url, headers={\"authorization\": \"...\"})\n)\n```\n\n```python\n# on server\nmcp_server = FastMCP(\"example\", transport=\"sse\")\n\nasync def handle_call_tool(\n self: FastMCP, req: types.CallToolRequest # \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\n) -\u003e Sequence[types.TextContent | types.ImageContent | types.EmbeddedResource]:\n headers = {}\n if \"authorization\" in req.headers:\n headers = {\"Authorization\": req.headers[\"authorization\"]}\n # ...http client call to api or if MCP is served from the app itself, check the key\n```\n\nI know auth is a part of the 2025 H1 roadmap so this may be usurped already in terms of how things will be supported. This goes beyond auth headers though since it could be useful to have access to the raw request in total instead within the tool execution context.","author":{"url":"https://github.com/mconflitti-pbc","@type":"Person","name":"mconflitti-pbc"},"datePublished":"2025-02-07T18:37:51.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":10},"url":"https://github.com/195/python-sdk/issues/195"}
| 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:f38067ec-5c9c-f4eb-ef7c-a3e86ee60c0c |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | CE60:168706:1442CC9:1CF774C:6A5A228B |
| html-safe-nonce | 1fb0457952a80bc70ddcca470426fc437da951ffbdd02ba61573a40c7a967206 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJDRTYwOjE2ODcwNjoxNDQyQ0M5OjFDRjc3NEM6NkE1QTIyOEIiLCJ2aXNpdG9yX2lkIjoiMTYxMzA5NjMzNjk4Mjk0MjM0NyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 3febbc334f31f98d60f7b275eb520a370c5b3488db8cd3aa58c79ecf39787f47 |
| hovercard-subject-tag | issue:2838832293 |
| 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/195/issue_layout |
| twitter:image | https://opengraph.githubassets.com/2d61cbcdbfdb0f06f53eda6d503b3cedf541b2f934123f068759d555b07d8015/modelcontextprotocol/python-sdk/issues/195 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/2d61cbcdbfdb0f06f53eda6d503b3cedf541b2f934123f068759d555b07d8015/modelcontextprotocol/python-sdk/issues/195 |
| og:image:alt | Is your feature request related to a problem? Please describe. I have an MCP server that sits in front of my API to allow LLMs to interact with it. My API requires an authorization header. I have h... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | mconflitti-pbc |
| hostname | github.com |
| expected-hostname | github.com |
| None | e31742e80bbd077fd5679c13ed870ce4e0c13803a2fa5beaae557b6769de2c8a |
| 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 | c9fcdbf98c619d1561ed843fa01d9766a32b5cd9 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width