chore: remove .coverage file and update .gitignore to exclude coverage files
- Deleted the .coverage file to clean up the repository. - Updated .gitignore to ensure .coverage and .coverage.* files are ignored in future commits. - Revised README.md to enhance clarity and conciseness regarding the library's capabilities and performance. - Improved documentation for the MCP server, emphasizing its expanded functionality and integration with clients.
This commit is contained in:
+120
-54
@@ -1,42 +1,56 @@
|
||||
# MCP Server — Connect ferro-ta in Cursor
|
||||
# MCP Server
|
||||
|
||||
ferro-ta ships an MCP (Model Context Protocol) server that exposes
|
||||
indicators and backtest tools to AI agents. This guide shows how to run
|
||||
the server and connect it to Cursor or any MCP-compatible client.
|
||||
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`
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
The MCP server requires no additional dependencies beyond ferro_ta itself.
|
||||
For the full MCP SDK integration (recommended), install the optional extra:
|
||||
Install the optional MCP extra:
|
||||
|
||||
```bash
|
||||
pip install "ferro-ta[mcp]"
|
||||
```
|
||||
|
||||
or install the `mcp` package separately:
|
||||
If you are working from this repository, you can install the same extra into
|
||||
the project environment with:
|
||||
|
||||
```bash
|
||||
pip install "mcp>=1.0"
|
||||
uv sync --extra mcp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Running the server
|
||||
|
||||
Run the server over stdio:
|
||||
|
||||
```bash
|
||||
python -m ferro_ta.mcp
|
||||
```
|
||||
|
||||
The server listens on stdin/stdout using JSON-RPC 2.0 (the MCP protocol).
|
||||
The command exits immediately with an install hint if the optional `mcp`
|
||||
dependency is missing.
|
||||
|
||||
---
|
||||
|
||||
## Connect in Cursor
|
||||
|
||||
1. Open Cursor settings (Command Palette → "Open User Settings (JSON)").
|
||||
2. Find or create the `mcpServers` section:
|
||||
Add the server to Cursor's MCP settings:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -44,82 +58,134 @@ The server listens on stdin/stdout using JSON-RPC 2.0 (the MCP protocol).
|
||||
"ferro-ta": {
|
||||
"command": "python",
|
||||
"args": ["-m", "ferro_ta.mcp"],
|
||||
"description": "ferro_ta — Technical Analysis MCP server"
|
||||
"description": "ferro-ta technical analysis tools"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Reload Cursor (Command Palette → "Developer: Reload Window").
|
||||
4. The ferro-ta tools will appear in the Tools panel.
|
||||
You can place this in your user settings JSON or in a workspace-level
|
||||
`.cursor/mcp.json`.
|
||||
|
||||
### Workspace-level config
|
||||
---
|
||||
|
||||
You can also add the config to your project's `.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
|
||||
|
||||
---
|
||||
|
||||
## Stateful classes and object references
|
||||
|
||||
Class tools return stored object references instead of plain text placeholders.
|
||||
For example, calling `TickAggregator` or `AlertManager` returns a payload like:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ferro-ta": {
|
||||
"command": "python",
|
||||
"args": ["-m", "ferro_ta.mcp"]
|
||||
}
|
||||
}
|
||||
"instance_id": "tickaggregator-0001",
|
||||
"type": "ferro_ta.data.aggregation.TickAggregator",
|
||||
"repr": "TickAggregator(rule='tick:2')"
|
||||
}
|
||||
```
|
||||
|
||||
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`.
|
||||
|
||||
---
|
||||
|
||||
## Callable references
|
||||
|
||||
Some ferro-ta APIs accept other callables, for example `benchmark`,
|
||||
`log_call`, `traced`, or `multi_timeframe(indicator=...)`.
|
||||
|
||||
Pass public ferro-ta callables using:
|
||||
|
||||
```json
|
||||
{"callable": "SMA"}
|
||||
```
|
||||
|
||||
Pass stored objects using:
|
||||
|
||||
```json
|
||||
{"instance_id": "function-0001"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example prompts
|
||||
|
||||
Once connected, you can ask Claude (or any MCP-enabled AI) things like:
|
||||
Once connected, you can ask an MCP-compatible client things like:
|
||||
|
||||
> "Compute RSI(14) on this price series: [100, 102, 101, 105, 108, 104, 107]"
|
||||
> "Run `SMA` with `close=[100, 101, 102, 103, 104]` and `timeperiod=3`."
|
||||
|
||||
> "Run a backtest with the rsi_30_70 strategy on [100, 101, 99, 103, 106, 102, 108, 105, 109, 112, 108, 111]"
|
||||
> "Use `compute_indicator` to calculate `MACD` for this close series."
|
||||
|
||||
> "List all available ferro_ta indicators"
|
||||
> "Call `about` and summarize the current ferro-ta API surface."
|
||||
|
||||
> "What does the SMA indicator do?"
|
||||
> "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."
|
||||
|
||||
---
|
||||
|
||||
## Available tools
|
||||
## Programmatic use
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `sma` | Simple Moving Average |
|
||||
| `ema` | Exponential Moving Average |
|
||||
| `rsi` | Relative Strength Index |
|
||||
| `macd` | MACD line, signal, histogram |
|
||||
| `backtest` | Vectorized backtest (rsi_30_70, sma_crossover, macd_crossover) |
|
||||
| `list_indicators` | List all registered indicators |
|
||||
| `describe_indicator` | Describe a named indicator |
|
||||
|
||||
---
|
||||
|
||||
## Programmatic use (Python client)
|
||||
|
||||
You can also use the MCP handlers directly in Python without the server:
|
||||
Use the server entrypoint:
|
||||
|
||||
```python
|
||||
from ferro_ta.mcp import handle_list_tools, handle_call_tool
|
||||
import numpy as np
|
||||
from ferro_ta.mcp import create_server
|
||||
|
||||
server = create_server()
|
||||
# server.run(transport="stdio")
|
||||
```
|
||||
|
||||
Or call the handlers directly without starting the server:
|
||||
|
||||
```python
|
||||
from ferro_ta.mcp import handle_call_tool, handle_list_tools
|
||||
import json
|
||||
|
||||
# List tools
|
||||
tools = handle_list_tools()
|
||||
print([t["name"] for t in tools["tools"]])
|
||||
print(len(tools["tools"]))
|
||||
|
||||
# Call RSI
|
||||
close = list(np.cumprod(1 + np.random.default_rng(0).normal(0, 0.01, 50)) * 100)
|
||||
result = handle_call_tool("rsi", {"close": close, "timeperiod": 14})
|
||||
print(result)
|
||||
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"]))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## See also
|
||||
|
||||
- `ferro_ta.mcp` — module source.
|
||||
- `ferro_ta.tools` — underlying tool functions.
|
||||
- `docs/agentic.md` — LangChain and workflow integration.
|
||||
- `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
|
||||
|
||||
Reference in New Issue
Block a user