Skip to content

Commit 2e3dfe1

Browse files
committed
chore: Added Tavily search tools.
1 parent db8a8fa commit 2e3dfe1

File tree

4 files changed

+42
-10
lines changed

4 files changed

+42
-10
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ There are Dapr related configuration files too.
4242

4343
The following API keys are optional but maybe provided for additional functionality. If not provided, the corresponding functionality will not be available.
4444

45-
- `OLLAMA_API_KEY`: The Ollama API key is required for MCP-based web search, web fetch and cloud hosted models on Ollama. MCP features include 2 tools. Create one from [your Ollama account](https://ollama.com/settings/keys).
45+
- `OLLAMA_API_KEY`: The Ollama API key is required for MCP-based web search, web fetch and cloud hosted models on Ollama. MCP features include 2 tools. Create an API key from [your Ollama account](https://ollama.com/settings/keys).
4646
- `ALPHAVANTAGE_API_KEY`: The API key to MCP-based Alpha Vantage finance related functions. MCP features include 118 tools. Obtain your [free API key from Alpha Vantage](https://www.alphavantage.co/support/#api-key). Note that basic finance tools are available through the [yfinance MCP](https://github.com/narumiruna/yfinance-mcp) even if Alpha Vantage MCP is not loaded.
47+
- `TAVILY_API_KEY`: The API key for Tavily search and research services. MCP features include 4 tools. Get your API key [from your Tavily account](https://app.tavily.com/home).
4748

4849
The following environment variables are all optional.
4950
- `APP_LOG_LEVEL`: The general log level of the DQA app. Defaults to `INFO`.

src/dqa/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class ParsedEnvVars:
5151
)
5252

5353
API_KEY_ALPHAVANTAGE: str = env.str("ALPHAVANTAGE_API_KEY", default=None)
54+
API_KEY_TAVILY: str = env.str("TAVILY_API_KEY", default=None)
5455
API_KEY_OLLAMA: str = env.str("OLLAMA_API_KEY", default=None)
5556

5657
_instance: ClassVar = None

src/dqa/mcp/primary.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,23 @@ def server():
4848
"No AlphaVantage API key found in environment variable 'API_KEY_ALPHAVANTAGE'. Skipping mounting AlphaVantage remote MCP."
4949
)
5050

51+
if ParsedEnvVars().API_KEY_TAVILY:
52+
# See: https://github.com/alphavantage/alpha_vantage_mcp
53+
tavily_remote_url = (
54+
f"https://mcp.tavily.com/mcp/?tavilyApiKey={ParsedEnvVars().API_KEY_TAVILY}"
55+
)
56+
tavily_remote_proxy = FastMCP.as_proxy(Client(tavily_remote_url))
57+
# Prefix is not necessary because Tavily tools are prefixed with "tavily_" already.
58+
server.mount(tavily_remote_proxy)
59+
logger.info("Mounted Tavily remote MCP.")
60+
logger.warning(
61+
"Tavily MCP is a rate-limited remote service, expect higher latency."
62+
)
63+
else:
64+
logger.warning(
65+
"No AlphaVantage API key found in environment variable 'TAVILY_API_KEY'. Skipping mounting Tavily remote MCP."
66+
)
67+
5168
if ParsedEnvVars().API_KEY_OLLAMA:
5269
server.mount(ollama_mcp(), prefix="ollama")
5370
logger.info("Mounted Ollama MCP.")

tests/test_primary_mcp.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
from dqa.mcp.primary import server as primary_mcp
55
from tests.mcp_test_mixin import MCPTestMixin
66

7+
from itertools import combinations
8+
79

810
class TestPrimaryMCP(MCPTestMixin):
911
# No need to test each MCP exhaustively here, they have their own tests.
@@ -34,17 +36,28 @@ def test_composition(self, mcp_client):
3436
"""
3537
Test that the primary MCP server has composed the necessary MCPs correctly.
3638
"""
39+
40+
def possible_tool_counts(base: int, additions: list[int]) -> set[int]:
41+
"""
42+
Given a base count and a list of possible additions, return all possible total counts.
43+
"""
44+
45+
counts = {base}
46+
for r in range(1, len(additions) + 1):
47+
for combo in combinations(additions, r):
48+
counts.add(base + sum(combo))
49+
return counts
50+
3751
n_base_tools = 22 # Base tools from local MCPs
3852
n_ollama_tools = 2
3953
n_alphavantage_tools = 118
54+
n_tavily_tools = 4
4055
tools = asyncio.run(self.list_tools(mcp_client))
41-
assert len(tools) in [
42-
# Base
56+
assert len(tools) in possible_tool_counts(
4357
n_base_tools,
44-
# With Ollama only
45-
n_base_tools + n_ollama_tools,
46-
# With AlphaVantage only
47-
n_base_tools + n_alphavantage_tools,
48-
# With both Ollama and AlphaVantage
49-
n_base_tools + n_ollama_tools + n_alphavantage_tools,
50-
]
58+
[
59+
n_ollama_tools,
60+
n_alphavantage_tools,
61+
n_tavily_tools,
62+
],
63+
)

0 commit comments

Comments
 (0)