2025, Oct 27 19:00

Why python-a2a to_langchain_tool fails with FastMCP (GET /mcp/tools) and what to use instead

Diagnose python-a2a LangChain failures with FastMCP: GET /mcp/tools 404/406 vs POST /mcp. Learn working HTTP setup, async client usage, and next steps.

Turning a local MCP Server into a LangChain tool with python-a2a sounds straightforward, yet it can fail with an MCPToolConversionError and a 404. The snag isn’t your FastMCP server itself: the trouble comes from how python-a2a attempts to fetch tools from the MCP endpoint.

Minimal setup that reproduces the issue

The LangChain adapter call is simple. It targets an MCP endpoint and requests a specific tool.

from python_a2a.langchain import to_langchain_tool
lc_tool_obj = to_langchain_tool("http://localhost:8080/mcp", "add")
print(lc_tool_obj)

A basic MCP Server with FastMCP might look like this.

from fastmcp import FastMCP
svc = FastMCP("Demo", stateless_http=True)
@svc.tool
def add(a: int, b: int) -> int:
    total = a + b
    print(total)
    return total
if __name__ == "__main__":
    svc.run()

Calling the server through fastmcp.client succeeds. It lists tools and invokes the add tool as expected, but the code must be executed in an async function and started with asyncio.run.

import asyncio
from fastmcp.client import Client
async def main():
    http_client = Client("http://localhost:8080/mcp")
    async with http_client:
        tool_list = await http_client.list_tools()
        print(tool_list)
        outcome = await http_client.call_tool("add", arguments={"a": 10, "b": 20})
        print(outcome.content)
if __name__ == "__main__":
    asyncio.run(main())

Despite this, the python-a2a adapter fails with a 404.

What actually goes wrong

The MCP endpoint exposed by FastMCP responds to POST requests under /mcp. When the fastmcp client asks for the tool list, the server logs show POST traffic and a redirect followed by a 200 OK.

INFO:     127.0.0.1:43026 - "POST /mcp HTTP/1.1" 307 Temporary Redirect
INFO:     127.0.0.1:43026 - "POST /mcp/ HTTP/1.1" 200 OK

In contrast, python-a2a v0.5.9 calls a different URL and uses the wrong HTTP method. Its to_langchain_tool() hits a GET endpoint that FastMCP does not serve for tool discovery, resulting in 406 or 404 depending on the server’s response path.

INFO:     127.0.0.1:47460 - "GET /mcp/tools HTTP/1.1" 406 Not Acceptable

The behavior comes directly from the adapter’s source, which constructs a GET against a /tools path.

tools_response = requests.get(f"{mcp_url}/tools")

Because the server expects POST to /mcp and not GET to /mcp/tools, the adapter fails with MCPToolConversionError and reports a 404.

Fixes you can apply right now

Two adjustments are necessary on your side, but they won’t fully resolve the adapter problem by themselves. First, ensure your FastMCP server is reachable over HTTP rather than stdio by selecting the proper transport. Second, drive the client in an async entry point with asyncio.run, which is mandatory for correct execution.

Here is a server configuration that uses the HTTP transport.

from fastmcp import FastMCP
svc = FastMCP("Demo", transport="streamable-http")
@svc.tool
def add(a: int, b: int) -> int:
    total = a + b
    print(total)
    return total
if __name__ == "__main__":
    svc.run()

And here is the async client invocation, which already works correctly with FastMCP.

import asyncio
from fastmcp.client import Client
async def main():
    http_client = Client("http://localhost:8080/mcp")
    async with http_client:
        tool_list = await http_client.list_tools()
        print(tool_list)
        outcome = await http_client.call_tool("add", arguments={"a": 10, "b": 20})
        print(outcome.content)
if __name__ == "__main__":
    asyncio.run(main())

The key point remains: even with a proper HTTP transport and a correct async client, to_langchain_tool() in python-a2a still issues GET /mcp/tools and fails. That mismatch sits in the adapter and needs to be addressed upstream. The problem has been reported to the python-a2a maintainers: https://github.com/themanojdesai/python-a2a/issues/74.

Why this matters for your stack

Converting MCP servers into LangChain tools is a valuable integration path, but subtle protocol mismatches can derail it. Understanding how the server expects requests (POST to /mcp) and what the adapter actually sends (GET to /mcp/tools) helps you quickly distinguish misconfiguration from adapter-level defects. It also prevents chasing 404 and 406 errors on the wrong side of the stack.

Conclusion and practical advice

If you need immediate functionality, interact with your MCP Server using fastmcp.client and an async entry point. Run the server with an HTTP transport such as streamable-http so it’s reachable over HTTP. For the LangChain tool conversion, wait for a fix in python-a2a’s to_langchain_tool(), since the current implementation performs a GET against a /tools path that FastMCP does not serve for discovery. Track the upstream issue for resolution and avoid relying on to_langchain_tool() in production until the adapter aligns with the MCP HTTP flow.

The article is based on a question from StackOverflow by JayantSeth and an answer by furas.