Conversation
| if result is None: | ||
| return HttpResponse(status=204) | ||
|
|
||
| response = JsonResponse(result, status=200) |
Check warning
Code scanning / CodeQL
Information exposure through an exception Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 16 hours ago
In general, to fix information exposure through exceptions, keep detailed error information (messages, stack traces) in server-side logs and return only generic, high-level error messages to clients. This preserves debuggability for developers without revealing internal details to callers.
For this specific code, the risky behavior is in backend/hexa/mcp/protocol.py in the handle_jsonrpc function, inside the if method == "tools/call": block. On exception, we currently build a JSON-RPC result that includes "text": str(e). We should instead:
- Keep the
logger.exception("Tool call failed: %s", tool_name)call so the full traceback is logged. - Replace the client-facing
"text": str(e)with a generic error string that does not include details from the exception, e.g."Tool call failed"or"An internal error occurred while running the tool.". - Optionally, include the tool name or a generic hint if that is acceptable from a privacy standpoint, but avoid echoing exception contents or stack traces.
No changes are needed in backend/hexa/mcp/views.py; the mcp_endpoint view can continue to return the JSON returned by handle_jsonrpc. Only handle_jsonrpc’s error payload needs to be adjusted.
Concretely:
- Edit
backend/hexa/mcp/protocol.pyaround lines 106–115. - In the returned dict under
"content", replacestr(e)with a hard-coded, non-sensitive message. - Do not modify imports or logging configuration.
| @@ -109,7 +109,12 @@ | ||
| "jsonrpc": "2.0", | ||
| "id": req_id, | ||
| "result": { | ||
| "content": [{"type": "text", "text": str(e)}], | ||
| "content": [ | ||
| { | ||
| "type": "text", | ||
| "text": "An internal error occurred while running the tool.", | ||
| } | ||
| ], | ||
| "isError": True, | ||
| }, | ||
| } |
| "ACCESS_TOKEN_EXPIRE_SECONDS": 3600, | ||
| "REFRESH_TOKEN_EXPIRE_SECONDS": 86400, |
There was a problem hiding this comment.
I have not tested expiration, something to consider, understand how tools are handling those expirations
| @@ -0,0 +1,82 @@ | |||
| query ListWorkspaces($query: String, $page: Int, $perPage: Int) { | |||
There was a problem hiding this comment.
Lets use our graphql layer to avoid code repetition
| token=token | ||
| ) | ||
| if access_token.expires >= timezone.now(): | ||
| request.user = access_token.user |
There was a problem hiding this comment.
The magic to scope actions to user
| def tool(func): | ||
| _TOOLS[func.__name__] = func | ||
| return func |
There was a problem hiding this comment.
No framework/library, just a small registry of tools
| return func(**arguments) | ||
|
|
||
|
|
||
| def handle_jsonrpc(body: bytes, user) -> dict | None: |
There was a problem hiding this comment.
Obviously some parts of this protocol is yet unclear to me (error numbers,...)
But I think we can live with unclear parts of a protocol as long as we verify security
| request.user = user | ||
| request.bypass_two_factor = True | ||
|
|
||
| result = graphql_sync( |
There was a problem hiding this comment.
Magic to query our graphql layer directly
| # TODO : those tools should be GraphQL mutations instead of REST endpoints, to be consistent with the rest of the API and to leverage GraphQL permissions, validation and audit (to be added). | ||
| # For now we keep them as simple tools for internal use, but we should migrate them to GraphQL in the future. |
There was a problem hiding this comment.
We can also ignore them for a v1. But this part of the impressive capabilities of the POC, writing files
In any case they need to be re-worked, don't want to merge those like this.
| ): | ||
| return redirect(f"{reverse(settings.LOGIN_URL)}?next={request.path}") | ||
| return redirect( | ||
| f"{reverse(settings.LOGIN_URL)}?next={quote(request.get_full_path())}" |
There was a problem hiding this comment.
Ensure the connection URL used by LLM tools is fully passed after the login blocker
| @@ -0,0 +1,201 @@ | |||
| import json | |||
There was a problem hiding this comment.
Lot of lack of understanding here but this is mostly a protocol with some configs
Deploy a remote MCP server with basic tools secured via OAuth 2.1
Note : some areas are not up to our standard quality but this PR serves as a POC to get early feedback and to understand where we should focus first
Changes
How/what to test
https://tommy-someurl-terese.ngrok-free.dev/mcpto configure it in Claude (https://tommy-someurl-terese.ngrok-free.dev/mcp)Screenshots / screencast
To go further