How To Build An Mcp Client For Fxmacrodata banner image

Implementation

How-To Guides

How To Build An Mcp Client For Fxmacrodata

Build a Python MCP client that connects to the FXMacroData remote server, lists tools, calls live macro data endpoints, and then extends into an LLM-powered chat workflow.

How to Build an MCP Client for FXMacroData

By FXMacroData Team
Published on June 10, 2026

This tutorial follows the shape of the official Build an MCP Client guide, but adapts it for a real remote server instead of a local demo process. By the end, you will have a Python client that connects to the production FXMacroData MCP endpoint, lists tools, and calls live macro data from USD inflation, the release calendar, and other FX workflows.

What you will build
A minimal Python MCP client that connects to https://fxmacrodata.com/mcp over Streamable HTTP, initializes a session, discovers tools, and calls them from code. Then you will see how to turn the same client into an LLM-powered research assistant.

Prerequisites

  • Python 3.11 or newer.
  • uv or pip for dependency management.
  • An FXMacroData API key if you want non-USD data, COT, or commodities. Public USD access works without a key.
  • A basic understanding of async Python.

If you only want to prove the connection first, you can use the public MCP URL with no credentials. That is enough for recent USD indicator queries, FX rates, catalogue lookups, and session status. When you want broader data such as policy rate comparisons across currencies or COT positioning, append your API key as a query parameter or use OAuth.


Step 1. Create the project and install the MCP SDK

The official tutorial starts with a local client project. Do the same here:

mkdir fxmd-mcp-client
cd fxmd-mcp-client
uv init
uv add mcp python-dotenv

If you prefer pip, this is equivalent:

python -m venv .venv
source .venv/bin/activate
pip install mcp python-dotenv

The key change from the official demo is transport. The tutorial on modelcontextprotocol.io shows a client that launches a local server over stdio. FXMacroData is hosted remotely, so your client will use the Python SDK's Streamable HTTP transport instead.


Step 2. Store the server URL and optional API key

Create a .env file in the project root:

FXMD_MCP_URL=https://fxmacrodata.com/mcp
FXMD_API_KEY=

Leave FXMD_API_KEY empty if you only want public USD access. When you are ready for protected tools, set it and the client will connect with:

https://fxmacrodata.com/mcp?api_key=YOUR_API_KEY

This is the quickest path for a custom client. For production user-facing apps, OAuth is usually better because it avoids shipping a shared API key inside your application.


Step 3. Write a minimal remote MCP client

Create client.py and add the following code:

import argparse
import asyncio
import json
import os
from urllib.parse import urlencode

from dotenv import load_dotenv
from mcp import ClientSession, types
from mcp.client.streamable_http import streamable_http_client


load_dotenv()


def build_server_url() -> str:
    base_url = os.getenv("FXMD_MCP_URL", "https://fxmacrodata.com/mcp")
    api_key = os.getenv("FXMD_API_KEY", "").strip()

    if not api_key or "api_key=" in base_url:
        return base_url

    separator = "&" if "?" in base_url else "?"
    return f"{base_url}{separator}{urlencode({'api_key': api_key})}"


def extract_content(result: types.CallToolResult) -> str:
    parts = []

    if result.structuredContent:
        parts.append(json.dumps(result.structuredContent, indent=2))

    for item in result.content:
        if isinstance(item, types.TextContent):
            parts.append(item.text)

    return "\n".join(parts).strip()


async def run() -> None:
    parser = argparse.ArgumentParser()
    parser.add_argument("command", choices=["tools", "call"])
    parser.add_argument("--tool", help="Tool name to call")
    parser.add_argument(
        "--args",
        default="{}",
        help='JSON object of tool arguments, for example: {"currency":"usd"}',
    )
    cli_args = parser.parse_args()

    server_url = build_server_url()

    async with streamable_http_client(server_url) as (
        read_stream,
        write_stream,
        _,
    ):
        async with ClientSession(read_stream, write_stream) as session:
            await session.initialize()

            if cli_args.command == "tools":
                tools = await session.list_tools()
                print(json.dumps([tool.model_dump() for tool in tools.tools], indent=2))
                return

            if not cli_args.tool:
                raise SystemExit("--tool is required when command=call")

            arguments = json.loads(cli_args.args)
            result = await session.call_tool(cli_args.tool, arguments)
            print(extract_content(result))


if __name__ == "__main__":
    asyncio.run(run())

This does four important things:

  1. Loads the production FXMacroData MCP URL from the environment.
  2. Appends ?api_key=... only when you actually have one.
  3. Uses streamable_http_client() instead of the local stdio_client() transport from the basic tutorial.
  4. Prints both structured JSON and plain-text tool output, which makes debugging much easier.

Step 4. Verify the connection and inspect the available tools

Start by listing tools:

uv run python client.py tools

You should see tools such as:

  • data_catalogue
  • indicator_query
  • release_calendar
  • forex
  • market_sessions

If you are following the official MCP tutorial closely, this is the remote equivalent of the "make sure the client can discover tools" checkpoint.

Now call the catalogue for public USD coverage:

uv run python client.py call --tool data_catalogue --args "{\"currency\":\"usd\"}"

Then pull recent inflation data:

uv run python client.py call --tool indicator_query --args "{\"currency\":\"usd\",\"indicator\":\"inflation\",\"start_date\":\"2025-01-01\",\"end_date\":\"2026-01-01\"}"

And finally inspect the next USD events on the release calendar:

uv run python client.py call --tool release_calendar --args "{\"currency\":\"usd\"}"

At this point you have a real MCP client, not just a config file entry inside an editor. That matters if you want to embed the workflow into your own backend, notebook helper, or research UI.


Step 5. Add a simple research workflow

Once tool discovery works, the next useful move is composing a few calls. For example, you can compare the most recent Federal Reserve context against EUR/USD by querying policy rates and spot in sequence.

Add this helper inside client.py if you want a concrete pattern:

async def quick_macro_snapshot(session: ClientSession) -> None:
    usd_rates = await session.call_tool(
        "indicator_query",
        {
            "currency": "usd",
            "indicator": "policy_rate",
            "start_date": "2024-01-01",
            "end_date": "2026-12-31",
        },
    )
    eur_rates = await session.call_tool(
        "indicator_query",
        {
            "currency": "eur",
            "indicator": "policy_rate",
            "start_date": "2024-01-01",
            "end_date": "2026-12-31",
        },
    )
    spot = await session.call_tool(
        "forex",
        {"base": "eur", "quote": "usd"},
    )

    print("USD policy rate:")
    print(extract_content(usd_rates))
    print("\nEUR policy rate:")
    print(extract_content(eur_rates))
    print("\nEUR/USD spot:")
    print(extract_content(spot))

This is also the point where authentication matters. The public server is enough for USD-only discovery and short-range public data. Multi-currency comparisons like EUR versus USD typically need a paid API key or an OAuth token.


Step 6. Turn the same MCP client into an LLM tool layer

The official build-client guide usually ends with a chatbot loop. The same idea works here: connect to FXMacroData first, then hand the discovered tool schemas to your model so it can decide when to call them.

The exact LLM provider is up to you. The important pattern is:

  1. Open the MCP session.
  2. Call list_tools().
  3. Convert those tools into your model provider's tool schema.
  4. When the model requests a tool call, execute it through session.call_tool().
  5. Feed the tool result back to the model and continue the loop.

A compact sketch looks like this:

async def chat_loop(session: ClientSession, llm_client, user_prompt: str) -> str:
    tools = await session.list_tools()

    tool_specs = [
        {
            "type": "function",
            "name": tool.name,
            "description": tool.description or "",
            "parameters": tool.inputSchema,
        }
        for tool in tools.tools
    ]

    messages = [{"role": "user", "content": user_prompt}]

    while True:
        response = llm_client.responses.create(
            model="gpt-4.1",
            input=messages,
            tools=tool_specs,
        )

        output = response.output[0]
        if output.type == "message":
            return output.content[0].text

        if output.type == "function_call":
            result = await session.call_tool(
                output.name,
                json.loads(output.arguments),
            )
            messages.append(output.model_dump())
            messages.append(
                {
                    "type": "function_call_output",
                    "call_id": output.call_id,
                    "output": extract_content(result),
                }
            )

The model name here is just an example. The real takeaway is architectural: FXMacroData stays the tool source, while your chosen model handles reasoning and language generation.


Step 7. Know when direct REST is still the better choice

MCP is ideal when you want discovery, tool schemas, and an agent loop. Direct REST is still better for deterministic scripts, cron jobs, and data pipelines.

For example, if you already know you only need one endpoint, a plain HTTP request is simpler:

curl "https://fxmacrodata.com/api/v1/announcements/usd/inflation?api_key=YOUR_API_KEY"

In practice, a good split is:

  • REST for stable production pulls and scheduled jobs.
  • MCP for exploratory research, chat interfaces, and agent-driven workflows.

If you are building an AI research assistant, you will often use both: MCP for the conversational tool layer, REST for the reproducible reporting and storage layer underneath.


Troubleshooting

  • You can list tools but protected calls fail. Your server connection works; your API key or OAuth token does not have access to that dataset.
  • The client fails before initialize(). Double-check that you are pointing at https://fxmacrodata.com/mcp and not a website page.
  • You only need a quick smoke test. Start with data_catalogue for usd, then try market_sessions.
  • You want user-by-user auth. Replace the query-param API key shortcut with OAuth and store tokens per user session.

Wrapping up

You now have the same core shape as the official MCP client tutorial, but pointed at a live remote server that is useful for macro and FX work. The crucial adaptation is swapping local stdio transport for remote Streamable HTTP, then treating FXMacroData as the tool source for your client.

From here, the sensible next steps are to add OAuth, persist conversation state, and build one concrete workflow around your highest-value use case, whether that is pre-market briefing, macro event monitoring, or pair-level research around releases and spot reactions.

Blogroll

AI Answer-Ready

Key Facts

Page
How To Build An MCP Client For FXmacrodata
Section
Articles
Canonical URL
https://fxmacrodata.com/articles/how-to-build-an-mcp-client-for-fxmacrodata
Source
FXMacroData editorial and official publisher references
Last Updated
2026-06-10 04:12 UTC

Provenance And Trust

Cite the canonical URL and source field above. Where available, this page maps to official publisher releases and timestamped updates.

Quick Q&A

What is this page about? This page explains How To Build An MCP Client For FXmacrodata with directly usable context for trading, research, and API workflows.

What source should be cited? Use the canonical URL and the listed source field; cite official publisher references when available.

How fresh is this content? The last updated value above reflects the page metadata or latest available data timestamp.

Can this be used in AI assistants? Yes. This section is intentionally structured for retrieval and citation in chat assistants.

Prompt Packs

Use these in ChatGPT, Claude, Gemini, Mistral, Perplexity, or Grok for consistent source-aware outputs.