2026-03-24 12:49:17 +05:30
|
|
|
# MCP Server
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
ferro-ta ships an optional MCP (Model Context Protocol) server built on the
|
|
|
|
|
official Python SDK's FastMCP layer. The server now exposes the broad public
|
|
|
|
|
ferro-ta callable surface instead of a tiny hand-picked subset.
|
|
|
|
|
|
|
|
|
|
That means MCP clients can use:
|
|
|
|
|
|
|
|
|
|
- Exact top-level ferro-ta exports such as `SMA`, `RSI`, `MACD`, `about`,
|
|
|
|
|
`methods`, `info`, `benchmark`, and `traced`
|
|
|
|
|
- Non-top-level public tools such as `compute_indicator`, `run_backtest`,
|
|
|
|
|
`check_cross`, `aggregate_ticks`, `TickAggregator`, and `AlertManager`
|
|
|
|
|
- Legacy lowercase convenience aliases: `sma`, `ema`, `rsi`, `macd`,
|
|
|
|
|
and `backtest`
|
|
|
|
|
- Generic instance tools for stateful classes and stored callables:
|
|
|
|
|
`list_instances`, `describe_instance`, `call_instance_method`,
|
|
|
|
|
`call_stored_callable`, and `delete_instance`
|
2026-03-23 23:34:28 +05:30
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Installation
|
|
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
Install the optional MCP extra:
|
2026-03-23 23:34:28 +05:30
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
pip install "ferro-ta[mcp]"
|
|
|
|
|
```
|
|
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
If you are working from this repository, you can install the same extra into
|
|
|
|
|
the project environment with:
|
2026-03-23 23:34:28 +05:30
|
|
|
|
|
|
|
|
```bash
|
2026-03-24 12:49:17 +05:30
|
|
|
uv sync --extra mcp
|
2026-03-23 23:34:28 +05:30
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Running the server
|
|
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
Run the server over stdio:
|
|
|
|
|
|
2026-03-23 23:34:28 +05:30
|
|
|
```bash
|
|
|
|
|
python -m ferro_ta.mcp
|
|
|
|
|
```
|
|
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
The command exits immediately with an install hint if the optional `mcp`
|
|
|
|
|
dependency is missing.
|
2026-03-23 23:34:28 +05:30
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Connect in Cursor
|
|
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
Add the server to Cursor's MCP settings:
|
2026-03-23 23:34:28 +05:30
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{
|
|
|
|
|
"mcpServers": {
|
|
|
|
|
"ferro-ta": {
|
|
|
|
|
"command": "python",
|
|
|
|
|
"args": ["-m", "ferro_ta.mcp"],
|
2026-03-24 12:49:17 +05:30
|
|
|
"description": "ferro-ta technical analysis tools"
|
2026-03-23 23:34:28 +05:30
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
You can place this in your user settings JSON or in a workspace-level
|
|
|
|
|
`.cursor/mcp.json`.
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## Tool naming
|
|
|
|
|
|
|
|
|
|
The MCP server prefers the real ferro-ta API names.
|
|
|
|
|
|
|
|
|
|
- Use exact public names when possible, for example `SMA`, `MACD`,
|
|
|
|
|
`compute_indicator`, `trade_stats`, `TickAggregator`, or `AlertManager`
|
|
|
|
|
- Use the legacy lowercase aliases only when you want the old MCP-friendly
|
|
|
|
|
shortcuts and result shapes
|
|
|
|
|
- Use `about`, `methods`, `indicators`, and `info` to discover what is
|
|
|
|
|
available from inside an MCP client
|
|
|
|
|
|
|
|
|
|
---
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
## Stateful classes and object references
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
Class tools return stored object references instead of plain text placeholders.
|
|
|
|
|
For example, calling `TickAggregator` or `AlertManager` returns a payload like:
|
2026-03-23 23:34:28 +05:30
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
{
|
2026-03-24 12:49:17 +05:30
|
|
|
"instance_id": "tickaggregator-0001",
|
|
|
|
|
"type": "ferro_ta.data.aggregation.TickAggregator",
|
|
|
|
|
"repr": "TickAggregator(rule='tick:2')"
|
2026-03-23 23:34:28 +05:30
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
Use that `instance_id` with:
|
|
|
|
|
|
|
|
|
|
- `describe_instance` to inspect the stored object and list public methods
|
|
|
|
|
- `call_instance_method` to call methods like `aggregate`, `update`,
|
|
|
|
|
`run_backtest`, or `to_dict`
|
|
|
|
|
- `delete_instance` to remove stored objects when you are done
|
|
|
|
|
|
|
|
|
|
If a tool returns a stored callable, use `call_stored_callable`.
|
|
|
|
|
|
2026-03-23 23:34:28 +05:30
|
|
|
---
|
|
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
## Callable references
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
Some ferro-ta APIs accept other callables, for example `benchmark`,
|
|
|
|
|
`log_call`, `traced`, or `multi_timeframe(indicator=...)`.
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
Pass public ferro-ta callables using:
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
```json
|
|
|
|
|
{"callable": "SMA"}
|
|
|
|
|
```
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
Pass stored objects using:
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
```json
|
|
|
|
|
{"instance_id": "function-0001"}
|
|
|
|
|
```
|
2026-03-23 23:34:28 +05:30
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
## Example prompts
|
|
|
|
|
|
|
|
|
|
Once connected, you can ask an MCP-compatible client things like:
|
|
|
|
|
|
|
|
|
|
> "Run `SMA` with `close=[100, 101, 102, 103, 104]` and `timeperiod=3`."
|
|
|
|
|
|
|
|
|
|
> "Use `compute_indicator` to calculate `MACD` for this close series."
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
> "Call `about` and summarize the current ferro-ta API surface."
|
|
|
|
|
|
|
|
|
|
> "Create a `TickAggregator` with `rule='tick:50'`, aggregate this tick data,
|
|
|
|
|
> then delete the instance."
|
|
|
|
|
|
|
|
|
|
> "Benchmark `SMA` over this price series using a callable reference."
|
2026-03-23 23:34:28 +05:30
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
## Programmatic use
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
Use the server entrypoint:
|
2026-03-23 23:34:28 +05:30
|
|
|
|
|
|
|
|
```python
|
2026-03-24 12:49:17 +05:30
|
|
|
from ferro_ta.mcp import create_server
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
server = create_server()
|
|
|
|
|
# server.run(transport="stdio")
|
|
|
|
|
```
|
2026-03-23 23:34:28 +05:30
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
Or call the handlers directly without starting the server:
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
from ferro_ta.mcp import handle_call_tool, handle_list_tools
|
|
|
|
|
import json
|
|
|
|
|
|
|
|
|
|
tools = handle_list_tools()
|
|
|
|
|
print(len(tools["tools"]))
|
|
|
|
|
|
|
|
|
|
close = [100, 101, 102, 103, 104]
|
|
|
|
|
result = handle_call_tool("SMA", {"close": close, "timeperiod": 3})
|
|
|
|
|
print(json.loads(result["content"][0]["text"]))
|
|
|
|
|
|
|
|
|
|
aggregator = json.loads(
|
|
|
|
|
handle_call_tool("TickAggregator", {"rule": "tick:2"})["content"][0]["text"]
|
|
|
|
|
)
|
|
|
|
|
bars = handle_call_tool(
|
|
|
|
|
"call_instance_method",
|
|
|
|
|
{
|
|
|
|
|
"instance_id": aggregator["instance_id"],
|
|
|
|
|
"method": "aggregate",
|
|
|
|
|
"args": [{"price": [1, 2, 3, 4], "size": [1, 1, 1, 1]}],
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
print(json.loads(bars["content"][0]["text"]))
|
2026-03-23 23:34:28 +05:30
|
|
|
```
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
## See also
|
|
|
|
|
|
2026-03-24 12:49:17 +05:30
|
|
|
- `python -m ferro_ta.mcp` - stdio MCP entrypoint
|
|
|
|
|
- `ferro_ta.mcp.create_server()` - FastMCP server factory
|
|
|
|
|
- `ferro_ta.tools.api_info` - API discovery helpers used by the MCP catalog
|
|
|
|
|
- `ferro_ta.tools` - stable wrappers such as `compute_indicator`
|
|
|
|
|
- `docs/agentic.md` - workflow and agent integration notes
|