12 min read

How to Build and Test AI Agents That Call External APIs

Build a local MCP tool server with FastMCP, expose it with a Localtonet HTTPS tunnel, and connect a LangChain agent to it from anywhere. No deployment needed for development and testing.

🤖 AI Agents · MCP · LangChain · Tool Servers · Local Development

How to Build and Test AI Agents That Call External APIs

AI agents are only useful when they can take actions in the real world querying a database, calling an API, reading a file, sending a message. The tool servers that expose those capabilities need a public URL to be reachable by agents running in the cloud or on another machine. This guide explains how the Model Context Protocol works, how to build a local tool server, and how a Localtonet HTTP tunnel gives it a public endpoint for testing and collaboration without deploying anything.

🔧 Model Context Protocol (MCP) 🐍 Python with FastMCP 🔗 LangChain integration 🌍 Public endpoint in under a minute

What Is the Model Context Protocol?

The Model Context Protocol (MCP) is an open standard developed by Anthropic that defines how AI agents discover and call external tools and data sources. Before MCP, every agent framework had its own way of defining tools OpenAI function calling, LangChain tools, custom REST wrappers. Each required its own integration code. MCP standardises the interface so a tool server built once can be used by any MCP-compatible agent, regardless of the underlying model or framework.

The architecture is straightforward. A tool server exposes a set of functions over HTTP or stdio. An agent connects to the server, discovers the available tools, and calls them as part of its reasoning loop. The agent does not need to know how the tools are implemented it only needs the server URL and the tool descriptions.

MCP in one sentence

MCP is to AI agents what a REST API is to web applications: a standard interface that lets any client talk to any server without custom integration code.

🔌 Model agnostic Works with GPT-4, Claude, Gemini, Llama, and any other LLM that supports tool calling. Build the server once.
🧩 Framework agnostic Compatible with LangChain, LangGraph, OpenAI Agents SDK, Claude desktop, and any other MCP-compatible host.
🔍 Dynamic discovery Agents discover available tools at runtime by asking the server. No need to predefine tool schemas in agent code.
🌐 HTTP and stdio transports Local tool servers use stdio. Remote servers use HTTP. The agent code is identical for both.

The Localhost Problem for AI Agent Development

When you build a tool server locally and run an agent on the same machine, everything works. The agent calls http://localhost:8000/mcp and the server responds. The problem starts the moment the agent runs somewhere other than your laptop.

☁️ Agent running in the cloud

LangGraph Cloud, LangSmith, n8n cloud, and similar platforms run your agent on their infrastructure. When the agent tries to call http://localhost:8000/mcp, it looks for that address on the cloud server not your laptop. The connection fails immediately.

👥 Sharing with a teammate

You want a colleague to test the tool server you built. They run the agent on their machine and point it at your server. Your server is on localhost. Their localhost is their machine. They cannot reach yours without a public address.

🖥️ Claude Desktop or VS Code Copilot

MCP-compatible clients like Claude Desktop can connect to remote HTTP tool servers. To use your locally running tool server from Claude Desktop on a different machine, the server needs a public HTTPS URL. Stdio transport only works when client and server run on the same machine.

The solution is to give your local tool server a public HTTPS URL using a Localtonet HTTP tunnel. The tunnel runs on your laptop alongside the server, forwards traffic from the public relay address to your local port, and the agent connects to the relay URL instead of localhost. Nothing else changes.

Build a Local MCP Tool Server

The fastest way to build an MCP tool server in Python is with FastMCP, which handles the protocol details and lets you focus on writing the actual tools as plain Python functions.

1

Install the dependencies

pip install fastmcp httpx
2

Create the tool server

This example builds a weather tool server that fetches real data from the Open-Meteo API (free, no API key required) and a currency conversion tool. Both are things an agent might genuinely need to do.

# server.py
import httpx
from fastmcp import FastMCP

mcp = FastMCP("My Tool Server")

@mcp.tool()
async def get_weather(latitude: float, longitude: float) -> dict:
    """Get current weather for a location using coordinates."""
    url = "https://api.open-meteo.com/v1/forecast"
    params = {
        "latitude": latitude,
        "longitude": longitude,
        "current": "temperature_2m,wind_speed_10m,weather_code",
        "temperature_unit": "celsius"
    }
    async with httpx.AsyncClient() as client:
        response = await client.get(url, params=params)
        data = response.json()
        return data["current"]

@mcp.tool()
async def convert_currency(amount: float, from_currency: str, to_currency: str) -> dict:
    """Convert an amount from one currency to another using live exchange rates."""
    url = f"https://open.er-api.com/v6/latest/{from_currency.upper()}"
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
        data = response.json()
        if data["result"] != "success":
            return {"error": "Could not fetch exchange rates"}
        rate = data["rates"].get(to_currency.upper())
        if not rate:
            return {"error": f"Unknown currency: {to_currency}"}
        return {
            "from": from_currency.upper(),
            "to": to_currency.upper(),
            "amount": amount,
            "converted": round(amount * rate, 4),
            "rate": rate
        }

if __name__ == "__main__":
    mcp.run(transport="http", host="127.0.0.1", port=8000)
3

Start the server

python server.py

The server listens at http://127.0.0.1:8000/mcp. Verify it is running by fetching the tool list:

curl http://127.0.0.1:8000/mcp/tools/list

Give the Tool Server a Public URL with Localtonet

With the server running on 127.0.0.1:8000, create an HTTP tunnel in Localtonet to give it a public HTTPS endpoint.

1

Install Localtonet and authenticate

localtonet --authtoken <YOUR_TOKEN>
2

Create an HTTP tunnel for port 8000

Go to the HTTP tunnel page, set local IP to 127.0.0.1 and port to 8000. Click Create and start the tunnel. The dashboard shows a public HTTPS URL such as https://abc123.localto.net.

3

Verify the public endpoint

curl https://abc123.localto.net/mcp/tools/list

If it returns your tool list, the server is reachable from anywhere on the internet. This URL is what you give to agents, teammates, and cloud platforms.

Connect a LangChain Agent to the Tool Server

LangChain's MCP adapter converts tool server endpoints into LangChain-compatible tool objects. Point the adapter at your Localtonet tunnel URL and the agent can call your tools from anywhere; your laptop, a cloud runner, a teammate's machine.

1

Install the LangChain MCP adapter

pip install langchain-mcp-adapters langgraph langchain-openai
2

Build the agent

# agent.py
import asyncio
import os
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI

# Replace with your actual Localtonet tunnel URL
MCP_SERVER_URL = "https://abc123.localto.net/mcp"

async def run_agent(query: str):
    client = MultiServerMCPClient({
        "my-tools": {
            "url": MCP_SERVER_URL,
            "transport": "http",
        }
    })

    tools = await client.get_tools()
    model = ChatOpenAI(model="gpt-4o", api_key=os.environ["OPENAI_API_KEY"])
    agent = create_react_agent(model, tools)

    response = await agent.ainvoke({
        "messages": [{"role": "user", "content": query}]
    })

    return response["messages"][-1].content

if __name__ == "__main__":
    result = asyncio.run(
        run_agent("What is the weather in Istanbul right now? Also convert 100 USD to EUR.")
    )
    print(result)
OPENAI_API_KEY=your_key python agent.py

The agent receives the query, discovers the available tools from the MCP server over HTTPS, calls get_weather and convert_currency as needed, and returns a natural language answer. All tool calls go through the Localtonet tunnel to your local server.

Using a local model instead of OpenAI

Replace ChatOpenAI with any LangChain-compatible model. To use a local Ollama model, install langchain-ollama and use ChatOllama(model="qwen2.5-coder:7b"). The MCP tool server and the Localtonet tunnel work identically regardless of which model the agent uses.

Testing Strategies for AI Agent Tool Servers

🔍 Test tools in isolation before connecting the agent

Before wiring an agent to your tool server, call the tools directly with curl or a Python script. Verify the inputs, outputs, and error handling without the complexity of agent reasoning on top. Once each tool returns the right data, the agent integration is straightforward.

# Call a specific tool directly via the MCP HTTP endpoint
curl -X POST https://abc123.localto.net/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{
    "name": "get_weather",
    "arguments": {"latitude": 41.01, "longitude": 28.95}
  }'
📝 Log every tool call during development

Add logging to each tool function so you can see exactly what inputs the agent sends and what your tool returns. When an agent produces a wrong answer, the tool call logs tell you whether the problem is in the tool logic or the agent reasoning.

import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

@mcp.tool()
async def get_weather(latitude: float, longitude: float) -> dict:
    """Get current weather for a location using coordinates."""
    logger.info(f"get_weather called: lat={latitude}, lon={longitude}")
    # ... tool logic
    logger.info(f"get_weather result: {result}")
    return result
🤝 Share the tunnel URL with teammates for collaborative testing

Send the Localtonet tunnel URL to a teammate working on the agent side of the project. They point their agent at your URL and test against your live tool implementation while you iterate on the server. No deployments, no Docker images to build, no environment setup. Stop the tunnel when the session is over.

🔄 Use Claude Desktop to test your server interactively

Claude Desktop supports MCP HTTP servers. Add your Localtonet tunnel URL to Claude Desktop's MCP configuration and interact with your tools through natural language in the desktop app. This gives you an instant, interactive test environment without writing any agent code.

// claude_desktop_config.json
{
  "mcpServers": {
    "my-local-tools": {
      "url": "https://abc123.localto.net/mcp",
      "transport": "http"
    }
  }
}

Frequently Asked Questions

What is the difference between MCP and regular function calling?

Function calling (OpenAI, Anthropic) lets a model call tools defined in the same API request. The tool schemas and implementations are embedded in the agent code. MCP externalises the tools into a separate server that the agent connects to at runtime. The agent discovers what tools are available by asking the server, rather than having them hardcoded. This means you can update or add tools on the server without changing the agent code, and the same server can be used by multiple different agents and frameworks simultaneously.

Can I use the tunnel URL with n8n or other automation platforms?

Yes. n8n supports MCP tool servers through its AI agent nodes. Point the server URL at your Localtonet tunnel address. The n8n cloud instance reaches your local tool server through the tunnel. This is particularly useful when you are prototyping a workflow that calls custom tools you are still actively developing you iterate locally and the cloud workflow picks up changes immediately.

Does the agent need to know about Localtonet?

No. The agent just sees an HTTPS URL. It has no knowledge of or dependency on Localtonet. The tunnel is transparent from the agent's perspective it is connecting to a normal HTTPS server. You can replace the tunnel URL with a real deployed server URL when you move to production and the agent code does not change at all.

How do I add authentication to my tool server?

For development sharing, Localtonet's SSO feature adds a login layer in front of the tunnel. For production, implement API key authentication directly in your FastMCP server by adding a middleware that checks for an Authorization header, or use FastMCP's built-in authentication support. Any client agent or otherwise must include the API key in its request headers to call the tools.

Can I run multiple tool servers on different ports and expose them all?

Yes. Create a separate Localtonet HTTP tunnel for each tool server port. Each gets its own public URL. In your MultiServerMCPClient configuration, list each server URL separately. The agent loads tools from all of them and can call any tool across any server in the same reasoning loop.

Should I keep the tunnel running permanently for an agent in production?

No. A Localtonet tunnel is ideal for development, testing, and temporary collaboration. For production agents that call tool servers continuously, deploy the tool server to a VPS or cloud instance so it has a stable, always-on address that does not depend on your laptop being awake. The development workflow in this guide lets you build and test everything locally before that deployment step.

Give Your Local Tool Server a Public Endpoint in Under a Minute

Build your MCP tool server locally, create a Localtonet HTTP tunnel, and share the URL with any agent or teammate. No deployment, no cloud infrastructure, no configuration changes.

Create Free Localtonet Account →

Localtonet is a secure multi-protocol tunneling and proxy platform designed to expose localhost, devices, private services, and AI agents to the public internet supporting HTTP/HTTPS tunnels, TCP/UDP forwarding, mobile proxy infrastructure, file server publishing, latency-optimized game connectivity, and developer-ready AI agent endpoint exposure from a single unified control plane.

support