You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add SSL Certificate Verification Options to FastMCP Client #870
Is your feature request related to a problem? Please describe.
When connecting to an MCP server over HTTPS with self-signed or internal certificates, the FastMCP Client fails with SSL certificate verification errors. Currently, there's no straightforward way to disable SSL verification or provide custom certificates when using the Client class.
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1007)
Describe the solution you'd like
Please add one or more of the following options to the FastMCP Client:
A verify parameter to disable SSL verification or to provide a custom certificate:
This is needed when working with internal or development environments that use self-signed certificates or private certificate authorities.
Describe alternatives you've considered
Users need to resort to insecure workarounds like patching Python's SSL module.
Additional context
The issue appears to be in how the transport is inferred and created from the URL string. When a URL is provided, the infer_transport function creates a StreamableHttpTransport for HTTPS URLs, but there's no way to configure the SSL verification options for this transport.
According to FastMCP requirements, streamable-http transport is required for web deployments, and the client needs to connect to the /mcp path. The current implementation doesn't provide a way to handle SSL verification for these connections.
This would align with how other HTTP client libraries (like requests) handle SSL verification, making the API more intuitive and flexible for enterprise environments.
MCP use httpx wich use certifi wich is an external trusted CA store not modifiable by user.
Certifi does not support any addition/removal or other modification of the CA trust store content. This project is intended to provide a reliable and highly portable root of trust to python deployments.
Source : https://github.com/certifi/python-certifi
An issue is open since 2019 for httpx to use the system trusted CA store instead : encode/httpx#302 but didn't seem to progress much.
Beside the fact it's really annoying to deal with "SSL: CERTIFICATE_VERIFY_FAILED" every time you use a self-signed certificate, it's a real security concern that httpx use a CA store that users can't modify/manage.
But things could be easy to deal with as httpx provide a simple way to use the system CA store :
This way all python projects using mcp will not have to deal with SSL issues on self-signed certificate and the security side will be handle by the user who will have to manually add the CA certificate to the system's truststore.
@cabusar, thank you so much for looking into this ticket! I'm still encountering SSL certificate verification issues with FastMCP. I've tried implementing the truststore approach you suggested, but I'm still facing challenges.
I have two specific questions:
Does FastMCP's Client create its own httpx client internally that might bypass our SSL context settings? If so, is there a way to provide the SSL context directly to FastMCP?
Instead of modifying certifi's cacert.pem directly, is there a way to configure FastMCP to use a custom certificate file path?
@iDataist : i'm not a contributor of this project, i was facing a similar issue with the python implementation of mcp and tried to help.
From my understanding of the problem : mcp use httpx with it's default parameters witch imply the use of certifi, a CA store that doesn't allow the modification of the CAs stored internally in ./venv/lib/python3.12/site-packages/certifi/cacert.pem (adapt regarding of your specific configuration).
mcp didn't offer the possibility to modify the behavior of httpx regarding which CA store to use, so you can't modify the "verify" option of the httpx instance created by mcp.
So, still in my understanding, and note that i'm not a good dev :
Have no effect in you script because certifi didn't take that into account.
client = Client(MCP_URL)
Here you create your instance of fastmcp which in the back use mcp, then httpx, but you have no control on how it's done regarding the "verify" parameter.
So, from here, three options :
mcp project implement a solution to control the verify parameter of httpx.
httpx project stop using certifi by default (which is a really curious/dumb choice from my adminsys perspective anyway)
You bypass entirely all this crap and just add your self-signed/generated CA in the certifi truststore (and froze the certifi dependancy to avoid any break caused by an update of certifi and it's truststore)
Keep in mind that the last "solution" should be really temporary, CA certificates are renewed regularly for security purposes, if you froze the CA store of certifi it could prevent legitimate certificate to be trusted in the futur.
The best solution would that httpx to change their approach of course.
As they seems not willing to do so, mcp dev would be really kind to offer a way to change the "verify" parameter of httpx.
@dsp-ant : David, if you have some time to look into this discussion it would be really kind (at least to tell if i understand the problem correctly). I would be glad to make a PR about it and save you some time, but given my coding skills you definitely don't want it to happen. ^^'
I updated the client library files to pass the verify=False parameter and then tried again and it worked.
Not the best solution rather temporary
Happy to raise a PR @ihrpr@dsp-ant
Could you do it by passing "verify=ssl_context" instead, making it safer and a more a long terme solution ?
Or even letting the user choosing between "default", "false" and "ssl_context" (or local_ca/a more understandable naming) ?
From what i see from _httpx_utils.py. the code is using the httpx._config.create_ssl_context to create ssl context and environment variable SSL_CERT_FILE/SSL_CERT_DIR should allow the us to add extra certs? then the context will use certifi if none of the environment variables are set.
It appears that when using https FastMCP server if you don't put a "/" at the end of the server URL configured in the MCP client then code 307 temporary redirects are sent from the server are not handled by the client. To prevent the redirects put a "/" at the end of the server URL in the MCP client.
I didn't need the httpx override mentioned above, and below worked.
async with streamablehttp_client("https://<host_port>/mcp/")
Same behavior observed when using and configuring a FastMCP client.
Full basic client code:
import asyncio
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async def main():
# Connect to a streamable HTTP server
#async with streamablehttp_client("http://localhost:8000/mcp") as (
async with streamablehttp_client("https://<host_port>/mcp/") as (
read_stream,
write_stream,
_,
):
# Create a session using the client streams
async with ClientSession(read_stream, write_stream) as session:
# Initialize the connection
await session.initialize()
# List available tools
tools = await session.list_tools()
print(f"Available tools: {[tool.name for tool in tools.tools]}")
if __name__ == "__main__":
asyncio.run(main())
# your imports here
# among them, there should be also:
# from mcp.server.fastmcp import FastMCP
class SecureFastMCP(FastMCP):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
async def run_streamable_http_async(self) -> None:
"""Run the server using StreamableHTTP transport."""
import uvicorn
starlette_app = self.streamable_http_app()
base_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "certs") # my certs are in the dir certs from where the file resides
config = uvicorn.Config(
starlette_app,
host = self.settings.host,
port = self.settings.port,
log_level = self.settings.log_level.lower(),
ssl_keyfile = os.getenv("SSL_KEY_FILE", os.path.join(base_dir, "key.pem")), # export SSL_KEY_FILE="/path/to/your/key.pem"
ssl_certfile = os.getenv("SSL_CERT_FILE", os.path.join(base_dir, "cert.pem")), # export SSL_CERT_FILE="/path/to/your/cert.pem"
)
print(self.streamable_http_app().routes)
server = uvicorn.Server(config)
logger.info("Starting secure FastMCP server...")
await server.serve()
mcp_server = SecureFastMCP(...)
# the rest of your code here
# don't forget to use @mcp_server.whatever(), where "whatever" can be "tools" and so on
if __name__ == "__main__":
mcp_server.run(transport = 'streamable-http')
Client Side
Let HTTPX/SSL use your environment variables (you can set them within Python script as well):
import asyncio
# if you would like to set here the env vars, don't forget about:
# import os
from mcp import ClientSession, Tool
from mcp.client.streamable_http import streamablehttp_client
async def main():
# here you should define your environment variables if you prefer them here
server_url = "https://<your_server>:<your_port>/mcp"
async with streamablehttp_client(server_url) as (read_stream, write_stream, _):
async with ClientSession(read_stream, write_stream) as client:
try:
print("Initializing session...")
session = await client.initialize()
print(f"Session initialized: {session}")
print("Listing tools...")
# tools = await client.list_tools()
tools = await client.list_tools()
print("Tools metadata keys:", [name for name, _ in tools])
print('Raw tools', tools.tools)
print(f'Registered tools: {[tool.name for tool in tools.tools]}')
# Use the 'add' tool, which requires the session ID for authentication.
print("Calling <my tool name> tool...")
result = await client.call_tool(<tool name>, <tool parameters as dict>)
print(f"Result of this call: {result.structuredContent['result']}")
except Exception as e:
print(f"An error occurred: {e}")
if __name__ == "__main__":
asyncio.run(main())
Test SSL
After starting the server, you can run the following file:
import os
import ssl, socket
host = '<your server IP>'
port = <your server port>
# PROTOCOL_TLS_CLIENT requires valid cert chain and hostname
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.load_verify_locations('/path/to/your/rootCA.pem')
with socket.create_connection((host, port)) as sock:
with context.wrap_socket(sock, server_hostname=host) as ssock:
print(ssock.version())
@felixweinberger any updates on the 2025-11-25 Implementation? And will this implementation allow users to do something like verify=False to address SSL Verification failed?
Ack, apologies - we didn't do anything specific in the spec here but I'll chase up the PR to make httpx.AsyncClient usable (#1177), I believe that would help here?
In the meantime, there is a workaround today: you can pass a custom httpx_client_factory to streamablehttp_client that returns a client with verify=False.
Activity
cabusar commentedon Jun 3, 2025
To add more detail to this issue :
MCP use httpx wich use certifi wich is an external trusted CA store not modifiable by user.
Certifi does not support any addition/removal or other modification of the CA trust store content. This project is intended to provide a reliable and highly portable root of trust to python deployments.
Source : https://github.com/certifi/python-certifi
An issue is open since 2019 for httpx to use the system trusted CA store instead : encode/httpx#302 but didn't seem to progress much.
Beside the fact it's really annoying to deal with "SSL: CERTIFICATE_VERIFY_FAILED" every time you use a self-signed certificate, it's a real security concern that httpx use a CA store that users can't modify/manage.
But things could be easy to deal with as httpx provide a simple way to use the system CA store :
Source :
encode/httpx#302 (comment)
This way all python projects using mcp will not have to deal with SSL issues on self-signed certificate and the security side will be handle by the user who will have to manually add the CA certificate to the system's truststore.
In addition this method is compatible with linux, windows and osx as "trustore" is designed to precisely do it that way :
https://github.com/sethmlarson/truststore
Hope this help. :)
PS :
One temporary workaround for those who are stuck :
In ./venv/lib/python3.12/site-packages/certifi/, edit cacert.pem, add the CA you generate with your self-signed certificate.
-----BEGIN CERTIFICATE-----
your cert here
-----END CERTIFICATE-----
iDataist commentedon Jun 3, 2025
@cabusar, thank you so much for looking into this ticket! I'm still encountering SSL certificate verification issues with FastMCP. I've tried implementing the truststore approach you suggested, but I'm still facing challenges.
I have two specific questions:
Does FastMCP's Client create its own httpx client internally that might bypass our SSL context settings? If so, is there a way to provide the SSL context directly to FastMCP?
Instead of modifying certifi's cacert.pem directly, is there a way to configure FastMCP to use a custom certificate file path?
cabusar commentedon Jun 3, 2025
@iDataist : i'm not a contributor of this project, i was facing a similar issue with the python implementation of mcp and tried to help.
From my understanding of the problem : mcp use httpx with it's default parameters witch imply the use of certifi, a CA store that doesn't allow the modification of the CAs stored internally in ./venv/lib/python3.12/site-packages/certifi/cacert.pem (adapt regarding of your specific configuration).
mcp didn't offer the possibility to modify the behavior of httpx regarding which CA store to use, so you can't modify the "verify" option of the httpx instance created by mcp.
So, still in my understanding, and note that i'm not a good dev :
Have no effect in you script because certifi didn't take that into account.
client = Client(MCP_URL)Here you create your instance of fastmcp which in the back use mcp, then httpx, but you have no control on how it's done regarding the "verify" parameter.
So, from here, three options :
Keep in mind that the last "solution" should be really temporary, CA certificates are renewed regularly for security purposes, if you froze the CA store of certifi it could prevent legitimate certificate to be trusted in the futur.
The best solution would that httpx to change their approach of course.
As they seems not willing to do so, mcp dev would be really kind to offer a way to change the "verify" parameter of httpx.
@dsp-ant : David, if you have some time to look into this discussion it would be really kind (at least to tell if i understand the problem correctly). I would be glad to make a PR about it and save you some time, but given my coding skills you definitely don't want it to happen. ^^'
cabusar commentedon Jun 15, 2025
Any update on this ?
jwthomp commentedon Jun 20, 2025
I work in a corporate environment that has this same problem when accessing any external resources due to the use of zscalar.
aniketwattamwar commentedon Jul 3, 2025
Is there a roadmap if this functionality would be added in the near future?
also @cabusar thank you for the detailed explanation
lucasalvarezlacasa commentedon Jul 7, 2025
Any updates on this?
aniketwattamwar commentedon Jul 8, 2025
I updated the client library files to pass the verify=False parameter and then tried again and it worked.
Not the best solution rather temporary
Happy to raise a PR @ihrpr @dsp-ant
cabusar commentedon Jul 8, 2025
Hi @aniketwattamwar,
I would love to see how you implemented this.
Could you do it by passing "verify=ssl_context" instead, making it safer and a more a long terme solution ?
Or even letting the user choosing between "default", "false" and "ssl_context" (or local_ca/a more understandable naming) ?
Akash321go commentedon Jul 8, 2025
Add import certifi_win32 at the very top, the SSL error went away.
aniketwattamwar commentedon Jul 10, 2025
Hi @Akash321go
Thank you for that input. Looks like the certifi_win32 is replaced with this pip_system_certs
I tried it and it worked for a deployed on prem application.
@cabusar
I did update the local library to accept the local ca .pem file as parameter with verify = True/False but cannot test it though.
eugenejen commentedon Jul 10, 2025
I met the same issue when we deploy mcp server internally behind internal CA. I am also interested to allow MCP client to be able to have local CA.
eugenejen commentedon Jul 10, 2025
From what i see from _httpx_utils.py. the code is using the httpx._config.create_ssl_context to create ssl context and environment variable SSL_CERT_FILE/SSL_CERT_DIR should allow the us to add extra certs? then the context will use certifi if none of the environment variables are set.
https://github.com/encode/httpx/blob/master/httpx/_config.py#L23-L70
Has anyone tried to use SSL_CERT_FILE or SSL_CERT_DIR successfully for mcp client?
suvojitkonar commentedon Jul 24, 2025
Hey i have figured this out :
ajainghub commentedon Jul 31, 2025
It appears that when using https FastMCP server if you don't put a "/" at the end of the server URL configured in the MCP client then code 307 temporary redirects are sent from the server are not handled by the client. To prevent the redirects put a "/" at the end of the server URL in the MCP client.
I didn't need the httpx override mentioned above, and below worked.
async with streamablehttp_client("https://<host_port>/mcp/")Same behavior observed when using and configuring a FastMCP client.
Full basic client code:
3 remaining items
felixweinberger commentedon Oct 7, 2025
This may be helped by #1177
gserbanut commentedon Oct 27, 2025
Here is a simple workaround:
Server Side
Override of FastMCP.run_streamable_http_async:
Client Side
Let HTTPX/SSL use your environment variables (you can set them within Python script as well):
Here is a working client for MCP v1.19.0
Test SSL
After starting the server, you can run the following file:
In my case, I got the output:
Enjoy your enterprise ready MCP!
josephfahimi commentedon Dec 8, 2025
@felixweinberger any updates on the 2025-11-25 Implementation? And will this implementation allow users to do something like verify=False to address SSL Verification failed?
felixweinberger commentedon Dec 8, 2025
Ack, apologies - we didn't do anything specific in the spec here but I'll chase up the PR to make
httpx.AsyncClientusable (#1177), I believe that would help here?In the meantime, there is a workaround today: you can pass a custom
httpx_client_factorytostreamablehttp_clientthat returns a client withverify=False.maxisbey commentedon Dec 10, 2025
Closing this as #1177 has now been merged. Feel free to reopen if you're still experiencing the issue after the fix!