<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Neurobro]]></title><description><![CDATA[Neurobro is personalized AI for finance across crypto, stocks and commodities. Here we share how we build it, how AI agents do market research, and hands-on gui]]></description><link>https://neurobro.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6ae2b13eeba02eb6e891bf68/6dfd34e5-9f78-4efe-88b5-c5e37443b546.png</url><title>Neurobro</title><link>https://neurobro.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sun, 01 Nov 2026 02:53:25 GMT</lastBuildDate><atom:link href="https://neurobro.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Add market research to your AI agent with one MCP tool]]></title><description><![CDATA[How to wire NeuroAPI into Claude Code, Cursor or VS Code over MCP, call the same agent from your code with REST, follow-ups and JSON schema output.]]></description><link>https://neurobro.hashnode.dev/add-market-research-to-your-ai-agent-with-one-mcp-tool</link><guid isPermaLink="true">https://neurobro.hashnode.dev/add-market-research-to-your-ai-agent-with-one-mcp-tool</guid><category><![CDATA[api]]></category><category><![CDATA[fintech]]></category><category><![CDATA[AI]]></category><category><![CDATA[mcp]]></category><dc:creator><![CDATA[Neurobro]]></dc:creator><pubDate>Thu, 29 Oct 2026 02:39:47 GMT</pubDate><content:encoded><![CDATA[<p>Every time I've tried to give an agent real market context, it turned into plumbing. One API for prices, another for news, a third for fundamentals, then a few hundred lines of glue so the model could make sense of it all.</p>
<p>So I tried something simpler: hand the whole question to a research agent and get an answer back. That's what <a href="https://neuroapi.neurobro.ai">NeuroAPI</a> does. It's Neurobro's research agent behind a single endpoint, and you can ask it about crypto, stocks, forex and commodities. It's also exposed as a remote MCP server with exactly one tool, so your editor's AI can call it directly.</p>
<p>This post walks through both paths: MCP first, because it takes about two minutes, then the REST API for when you want it inside your own app.</p>
<h2>What you need</h2>
<ul>
<li>A NeuroAPI key. You create it in the dashboard under API Keys. The full secret is shown once, so put it somewhere safe right away. Keys look like <code>neuro_...</code>.</li>
<li>An environment variable holding it:</li>
</ul>
<pre><code class="language-bash">export NEUROAPI_KEY="neuro_..."
</code></pre>
<p>Every snippet below reads the key from that variable. Don't hard-code it and don't commit it.</p>
<p>Quick sanity check before anything else. <code>GET /health</code> is an authenticated call that confirms the key and the connection:</p>
<pre><code class="language-bash">curl -s https://api.neurobro.ai/api/v1/health \
  -H "X-API-Key: $NEUROAPI_KEY" | jq
</code></pre>
<p>The docs show a response like this (your version number may differ):</p>
<pre><code class="language-json">{
  "status": "healthy",
  "service": "neuroapi",
  "version": "0.1.13",
  "authenticated": true,
  "key_prefix": "neuro_a1b2c3d4",
  "timestamp": "2026-05-08T12:34:56.789Z"
}
</code></pre>
<h2>Part 1: MCP in your editor</h2>
<p>The MCP server is remote and runs over Streamable HTTP, so there's nothing to install or host. You point your client at one URL:</p>
<pre><code>https://api.neurobro.ai/api/v1/mcp
</code></pre>
<p>Authentication uses the same <code>X-API-Key</code> header as the REST API. Never put the key in the URL; the server rejects keys in the query string with a 400.</p>
<h3>Claude Code</h3>
<p>Add a <code>.mcp.json</code> at your repo root. Claude Code expands <code>${VAR}</code> from your environment:</p>
<pre><code class="language-json">{
  "mcpServers": {
    "neuroapi": {
      "type": "http",
      "url": "https://api.neurobro.ai/api/v1/mcp",
      "headers": {
        "X-API-Key": "${NEUROAPI_KEY}"
      }
    }
  }
}
</code></pre>
<h3>Cursor</h3>
<p>Put this in <code>~/.cursor/mcp.json</code> (global) or <code>.cursor/mcp.json</code> (per project). Cursor uses <code>${env:VAR}</code>:</p>
<pre><code class="language-json">{
  "mcpServers": {
    "neuroapi": {
      "url": "https://api.neurobro.ai/api/v1/mcp",
      "headers": {
        "X-API-Key": "${env:NEUROAPI_KEY}"
      }
    }
  }
}
</code></pre>
<h3>VS Code</h3>
<p>Add <code>.vscode/mcp.json</code> to your workspace. The <code>"type": "http"</code> line matters: without it, VS Code treats the entry as a local command and tries to execute the URL. The <code>inputs</code> block prompts for the key once and keeps it in VS Code's secret storage:</p>
<pre><code class="language-json">{
  "servers": {
    "neuroapi": {
      "type": "http",
      "url": "https://api.neurobro.ai/api/v1/mcp",
      "headers": {
        "X-API-Key": "${input:neuroapi-key}"
      }
    }
  },
  "inputs": [
    {
      "id": "neuroapi-key",
      "type": "promptString",
      "description": "NeuroAPI API key",
      "password": true
    }
  ]
}
</code></pre>
<p>Clients that only speak stdio, like Claude Desktop, can connect through the <code>mcp-remote</code> bridge. The <a href="https://neuroapi.neurobro.ai/docs/mcp/clients">client setup page</a> has the exact config, including a gotcha about keeping the header value as a single token.</p>
<h3>Check that it worked</h3>
<p>Your client should list exactly one tool: <code>ask_neuroapi</code>. Then ask something like "What's the macro setup for the euro this week?" and watch it call the tool.</p>
<p>The tool takes the same inputs as the REST endpoint:</p>
<table>
<thead>
<tr>
<th>Input</th>
<th>Required</th>
<th>What it does</th>
</tr>
</thead>
<tbody><tr>
<td><code>prompt</code></td>
<td>yes</td>
<td>The question for the agent</td>
</tr>
<tr>
<td><code>message_history</code></td>
<td>no</td>
<td>Earlier <code>{role, content}</code> turns</td>
</tr>
<tr>
<td><code>system_prompt</code></td>
<td>no</td>
<td>Extra steering for tone or format</td>
</tr>
<tr>
<td><code>output_schema</code></td>
<td>no</td>
<td>A JSON Schema, so you get an object back instead of prose</td>
</tr>
</tbody></table>
<p>One thing to know: MCP tool calls aren't streamed. You get one complete answer. If you want tokens as they arrive, use the REST endpoint with streaming.</p>
<h2>Part 2: The REST API</h2>
<p>Everything goes through one endpoint: <code>POST https://api.neurobro.ai/api/v1/agent/ask</code>.</p>
<h3>A simple question</h3>
<pre><code class="language-python">import os, httpx

res = httpx.post(
    "https://api.neurobro.ai/api/v1/agent/ask",
    headers={"X-API-Key": os.environ["NEUROAPI_KEY"]},
    json={
        "prompt": "Summarise the latest macroeconomic outlook for the eurozone in one sentence."
    },
    timeout=60,
)
data = res.json()
print(data["answer"])
</code></pre>
<p>The response has <code>answer</code>, <code>request_id</code> and a <code>usage</code> block. Here's the sample from the quickstart, trimmed (the answer text is shortened in the docs too):</p>
<pre><code class="language-json">{
  "answer": "The European Central Bank held rates steady ...",
  "request_id": "8b3a2f0e-1d7e-4c6b-9b2a-f5e23a1c9d44",
  "usage": {
    "prompt_tokens": 124,
    "completion_tokens": 256
  }
}
</code></pre>
<p>Keep <code>request_id</code> around. It's also sent back as the <code>X-Request-Id</code> header, and it's the thing support will ask for if something goes wrong.</p>
<h3>Follow-up questions</h3>
<p>The API is stateless, so your code owns the conversation. Send earlier turns in <code>message_history</code> with roles <code>user</code> and <code>assistant</code>:</p>
<pre><code class="language-python">import os, httpx

def ask(prompt: str, history: list[dict]) -&gt; dict:
    res = httpx.post(
        "https://api.neurobro.ai/api/v1/agent/ask",
        headers={"X-API-Key": os.environ["NEUROAPI_KEY"]},
        json={"prompt": prompt, "message_history": history},
        timeout=60,
    )
    return res.json()

history = [
    {"role": "user", "content": "Compare AAPL and MSFT on FY2024 earnings growth."},
    {"role": "assistant", "content": "Both delivered double-digit YoY revenue growth, with..."},
]
print(ask("How did their gross margins evolve over the same period?", history)["answer"])
</code></pre>
<p>Instructions go in <code>system_prompt</code>, not in a <code>system</code> turn; those are accepted but ignored.</p>
<h3>Shaping the answer with a system prompt</h3>
<p><code>system_prompt</code> layers on top of the agent's built-in instructions. It can't override its persona or guardrails, but it's the cleanest way to make answers fit your UI:</p>
<pre><code class="language-python">import os, httpx

res = httpx.post(
    "https://api.neurobro.ai/api/v1/agent/ask",
    headers={"X-API-Key": os.environ["NEUROAPI_KEY"]},
    json={
        "prompt": "How is the EUR/USD pair looking this week?",
        "system_prompt": (
            "You are a concise FX strategist. Lead with a one-line bias "
            "(long/short/neutral), then three supporting bullets. Flag any "
            "figure you are not confident about."
        ),
    },
    timeout=60,
)
print(res.json()["answer"])
</code></pre>
<h3>Structured output</h3>
<p>This is my favourite part. Pass <code>output_schema</code> (a JSON Schema with an object root) and the result comes back in <code>output</code>, with <code>answer</code> set to null. No parsing free text.</p>
<pre><code class="language-python">import os, httpx

schema = {
    "type": "object",
    "properties": {
        "stance": {"type": "string", "enum": ["bullish", "bearish", "neutral"]},
        "conviction": {"type": "number", "description": "0-1 confidence"},
        "support": {"type": "number"},
        "resistance": {"type": "number"},
        "summary": {"type": "string"},
    },
    "required": ["stance", "conviction", "support", "resistance", "summary"],
    "additionalProperties": False,
}

res = httpx.post(
    "https://api.neurobro.ai/api/v1/agent/ask",
    headers={"X-API-Key": os.environ["NEUROAPI_KEY"]},
    json={
        "prompt": "Give me a structured read on Bitcoin right now.",
        "output_schema": schema,
    },
    timeout=120,
)
output = res.json()["output"]
print(output["stance"], output["conviction"])
</code></pre>
<p>The docs' example of what lands in <code>output</code>:</p>
<pre><code class="language-json">{
  "stance": "bullish",
  "conviction": 0.62,
  "support": 58000,
  "resistance": 72000,
  "summary": "Holding above the 50-day average with improving spot demand."
}
</code></pre>
<p>Two notes from the docs. Structured output is non-streaming only. And because the agent fetches live data before filling your schema, a call usually takes 10 to 60 seconds, so set your timeout to at least 120.</p>
<h3>Streaming</h3>
<p>For chat UIs, send <code>"stream": true</code> and read Server-Sent Events. Each <code>data:</code> line is a JSON object, text arrives in <code>data.answer.chunk.content</code>, and the stream ends with <code>data: [DONE]</code>:</p>
<pre><code class="language-python">import json, os, httpx

with httpx.stream(
    "POST",
    "https://api.neurobro.ai/api/v1/agent/ask",
    headers={"X-API-Key": os.environ["NEUROAPI_KEY"]},
    json={
        "prompt": "Walk me through a top-down technical read on NVDA right now.",
        "stream": True,
    },
    timeout=None,
) as res:
    for line in res.iter_lines():
        if not line.startswith("data: "):
            continue
        payload = line[len("data: "):]
        if payload == "[DONE]":
            break
        event = json.loads(payload)
        if event["type"] == "error":
            raise RuntimeError(event["message"])
        answer = event["data"]["answer"]
        if answer:
            print(answer["chunk"]["content"], end="", flush=True)
</code></pre>
<p>Only <code>[DONE]</code> means the answer is complete. If the run fails, the last event is an <code>error</code> and there's no <code>[DONE]</code>.</p>
<h2>Gold vs. NVDA vs. Bitcoin, side by side</h2>
<p>Here's the one that sold me. A question I actually ask myself: which of these three looks best right now? Instead of reading three different dashboards, I ask about each one with the same schema and line the answers up.</p>
<pre><code class="language-python">import os, httpx

ASSETS = ["gold", "NVDA", "Bitcoin"]

schema = {
    "type": "object",
    "properties": {
        "stance": {"type": "string", "enum": ["bullish", "bearish", "neutral"]},
        "conviction": {"type": "number", "description": "0-1 confidence"},
        "support": {"type": "number"},
        "resistance": {"type": "number"},
        "summary": {"type": "string"},
    },
    "required": ["stance", "conviction", "support", "resistance", "summary"],
    "additionalProperties": False,
}

def read(asset: str) -&gt; dict:
    res = httpx.post(
        "https://api.neurobro.ai/api/v1/agent/ask",
        headers={"X-API-Key": os.environ["NEUROAPI_KEY"]},
        json={
            "prompt": f"Give me a structured read on {asset} right now.",
            "output_schema": schema,
        },
        timeout=120,
    )
    res.raise_for_status()
    return res.json()["output"]

reads = {asset: read(asset) for asset in ASSETS}

for asset, r in sorted(reads.items(), key=lambda kv: kv[1]["conviction"], reverse=True):
    print(f"{asset:&lt;8} {r['stance']:&lt;8} {r['conviction']:.2f}  {r['summary']}")
</code></pre>
<p>Because every answer has the same shape, the "comparison" is just a sort. You can push the same dicts into a table, a chart or a Slack message without touching a parser. I kept one question per asset on purpose: each call stays focused, and if one fails you still get the other two.</p>
<h2>Putting it together: a morning watchlist brief</h2>
<p>Same idea, wider net. This one runs on a cron before I open any charts. It asks for a structured read on a few markets and writes the results to a JSON file you can feed into a dashboard or a chat message. The request shape is straight from the docs; the watchlist and file handling are mine.</p>
<pre><code class="language-python">import json, os, httpx

WATCHLIST = ["Bitcoin", "NVDA", "EUR/USD", "gold"]

schema = {
    "type": "object",
    "properties": {
        "stance": {"type": "string", "enum": ["bullish", "bearish", "neutral"]},
        "conviction": {"type": "number", "description": "0-1 confidence"},
        "summary": {"type": "string"},
    },
    "required": ["stance", "conviction", "summary"],
    "additionalProperties": False,
}

def read(market: str) -&gt; dict:
    res = httpx.post(
        "https://api.neurobro.ai/api/v1/agent/ask",
        headers={"X-API-Key": os.environ["NEUROAPI_KEY"]},
        json={
            "prompt": f"Give me a structured read on {market} right now.",
            "output_schema": schema,
        },
        timeout=120,
    )
    res.raise_for_status()
    body = res.json()
    return {"market": market, "request_id": body["request_id"], **body["output"]}

brief = [read(m) for m in WATCHLIST]

with open("brief.json", "w") as f:
    json.dump(brief, f, indent=2)
</code></pre>
<p>A few practical things the docs call out that are worth building in from day one:</p>
<ul>
<li>Retry only on 429 and 503, and honour <code>Retry-After</code>. Don't retry blindly on 500, because <code>/agent/ask</code> isn't idempotent. The <a href="https://neuroapi.neurobro.ai/docs/best-practices/examples">examples page</a> has a backoff helper.</li>
<li>Log <code>request_id</code> for every call.</li>
<li>Keep the key in an env var or secret manager, and revoke it from the dashboard if it leaks.</li>
</ul>
<p>And the obvious one: treat the answers as research input for your own decisions, not financial advice.</p>
<h2>Links</h2>
<ul>
<li>Docs: <a href="https://neuroapi.neurobro.ai/docs">neuroapi.neurobro.ai/docs</a></li>
<li>MCP overview: <a href="https://neuroapi.neurobro.ai/docs/mcp">neuroapi.neurobro.ai/docs/mcp</a></li>
<li>Client setup: <a href="https://neuroapi.neurobro.ai/docs/mcp/clients">neuroapi.neurobro.ai/docs/mcp/clients</a></li>
<li>Examples: <a href="https://neuroapi.neurobro.ai/docs/best-practices/examples">neuroapi.neurobro.ai/docs/best-practices/examples</a></li>
<li>Neurobro on X: <a href="https://x.com/0xNeurobro">@0xNeurobro</a></li>
</ul>
<p>That's the whole setup. If you build something with it, drop a link in the comments. I'd genuinely like to see it.</p>
]]></content:encoded></item></channel></rss>