Skip to content

Commit 0e3762f

Browse files
committed
add: add plot(matplotlib) and financial technical indicators' caculator tools, and add py test script
1 parent 7481e31 commit 0e3762f

13 files changed

+892
-4
lines changed

config/agent_quickstart_search.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ main_agent:
2424

2525
tool_config:
2626
- tool-searching-serper
27+
- tool-financial-search
28+
- tool-plot
29+
- tool-technical-indicators
2730

2831
max_turns: -1 # Maximum number of turns for main agent execution
2932
max_tool_calls_per_turn: 10 # Maximum number of tool calls per turn
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
name: "tool-financial-search"
2+
tool_command: "python"
3+
args:
4+
- "-m"
5+
- "src.tool.mcp_servers.financial_search_server"
6+
env:
7+
FINANCIAL_API_BASE_URL: "${oc.env:FINANCIAL_API_BASE_URL,http://localhost:8060}"

config/tool/tool-plot.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
name: "tool-plot"
2+
tool_command: "python"
3+
args:
4+
- "-m"
5+
- "src.tool.mcp_servers.plot_tool_mcp_server"
6+
env:
7+
# optional: configure default output dir via env if you want
8+
PLOT_OUTPUT_DIR: "${oc.env:PLOT_OUTPUT_DIR,./outputs/plots}"
Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
1+
# name: "tool-searching-serper"
2+
# tool_command: "npx"
3+
# args:
4+
# - "-y"
5+
# - "serper-search-scrape-mcp-server"
6+
# env:
7+
# # Search API key - this value will be loaded from the .env file at runtime
8+
# SERPER_API_KEY: "${oc.env:SERPER_API_KEY}"
9+
10+
111
name: "tool-searching-serper"
2-
tool_command: "npx"
12+
tool_command: "python"
313
args:
4-
- "-y"
5-
- "serper-search-scrape-mcp-server"
14+
- "-m"
15+
- "src.tool.mcp_servers.miroapi_serper_mcp_server"
616
env:
7-
# Search API key - this value will be loaded from the .env file at runtime
817
SERPER_API_KEY: "${oc.env:SERPER_API_KEY}"
18+
SERPER_BASE_URL: "${oc.env:SERPER_BASE_URL,https://google.serper.dev}"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
name: "tool-technical-indicators"
2+
tool_command: "python"
3+
args:
4+
- "-m"
5+
- "src.tool.mcp_servers.technical_indicator_mcp_server"
6+
env:
7+
# optional defaults
8+
# nothing required; manager will pass arguments at call time

output.md

Whitespace-only changes.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dependencies = [
1313
"fastmcp>=2.10.6",
1414
"google-genai>=1.28.0",
1515
"markitdown-mcp>=0.0.1a3",
16+
"matplotlib>=3.8.0",
1617
"mcp>=1.12.2",
1718
"mutagen>=1.47.0",
1819
"openai==1.78.1",
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# ...existing code...
2+
import os
3+
import json
4+
import requests
5+
from typing import Any, Dict, Optional
6+
from mcp.server.fastmcp import FastMCP
7+
8+
BASE_URL = os.getenv("FINANCIAL_API_BASE_URL", "http://localhost:8060")
9+
10+
mcp = FastMCP("financial-search-mcp-server")
11+
12+
13+
def _post(path: str, payload: Dict[str, Any], stream: bool = False) -> Dict[str, Any]:
14+
url = BASE_URL.rstrip("/") + path
15+
try:
16+
resp = requests.post(url, json=payload, stream=stream, timeout=30)
17+
resp.raise_for_status()
18+
if stream:
19+
# 收集流式返回的每一行 JSON(如果服务以行分块返回 JSON)
20+
items = []
21+
for line in resp.iter_lines(decode_unicode=True):
22+
if not line:
23+
continue
24+
try:
25+
items.append(json.loads(line))
26+
except Exception:
27+
# 如果不是 JSON,作为文本行保存
28+
items.append({"raw": line})
29+
return {"status": "success", "result": {"items": items}}
30+
else:
31+
body = resp.json()
32+
return {"status": "success", "result": body.get("result", body)}
33+
except requests.HTTPError as he:
34+
try:
35+
body = resp.json()
36+
except Exception:
37+
body = resp.text if resp is not None else str(he)
38+
return {"status": "error", "result": {"error": str(he), "body": body}}
39+
except Exception as e:
40+
return {"status": "error", "result": {"error": str(e)}}
41+
42+
43+
@mcp.tool()
44+
def get_stock_history(ticker: str, start_date: str, end_date: str) -> Dict[str, Any]:
45+
"""调用 /get_stock_history"""
46+
payload = {"ticker": ticker, "start_date": start_date, "end_date": end_date}
47+
return _post("/get_stock_history", payload, stream=False)
48+
49+
50+
@mcp.tool()
51+
def get_company_news(ticker: str, start_date: str, end_date: str, crawl_content: bool = True) -> Dict[str, Any]:
52+
"""调用 /get_company_news,服务如支持流式会按行聚合并返回 items 列表"""
53+
payload = {
54+
"ticker": ticker,
55+
"start_date": start_date,
56+
"end_date": end_date,
57+
"crawl_content": crawl_content,
58+
}
59+
return _post("/get_company_news", payload, stream=True)
60+
61+
62+
@mcp.tool()
63+
def get_general_news(start_date: str, end_date: str, crawl_content: bool = True, max_items: int = 100) -> Dict[str, Any]:
64+
payload = {
65+
"start_date": start_date,
66+
"end_date": end_date,
67+
"crawl_content": crawl_content,
68+
"max_items": max_items,
69+
}
70+
return _post("/get_general_news", payload, stream=True)
71+
72+
73+
@mcp.tool()
74+
def get_financials_reported(ticker: str, start_date: str, end_date: str, freq: str = "annual") -> Dict[str, Any]:
75+
payload = {"ticker": ticker, "start_date": start_date, "end_date": end_date, "freq": freq}
76+
return _post("/get_financials_reported", payload, stream=False)
77+
78+
79+
if __name__ == "__main__":
80+
# 以 FastMCP 的方式启动(根据你项目的 FastMCP 用法调整)
81+
try:
82+
mcp.run()
83+
except Exception:
84+
# 若 run 名称不同,改为 mcp.serve() 或按项目其他 MCP 启动方式
85+
pass

0 commit comments

Comments
 (0)