Add include_usage support

This commit is contained in:
Cursor Agent
2025-12-10 18:49:31 +00:00
parent 2be989a881
commit c8dad2daa0
2 changed files with 105 additions and 4 deletions
+37
View File
@@ -19,6 +19,43 @@ The Tavily MCP server provides:
- [Tutorial](https://medium.com/@dustin_36183/building-a-knowledge-graph-assistant-combining-tavily-and-neo4j-mcp-servers-with-claude-db92de075df9) on combining Tavily MCP with Neo4j MCP server
- [Tutorial](https://medium.com/@dustin_36183/connect-your-coding-assistant-to-the-web-integrating-tavily-mcp-with-cline-in-vs-code-5f923a4983d1) on integrating Tavily MCP with Cline in VS Code
## `include_usage` parameter
All Tavily API endpoints (`/search`, `/extract`, `/crawl`, `/map`) now accept an optional boolean `include_usage` flag. When set to `true`, the response includes a `usage` object that reports credit consumption for that request. The flag defaults to `false` so existing workflows remain fully backward compatible.
> Credit usage may be reported as `0` until certain usage thresholds are reached. The exact behavior can vary by endpoint.
### API endpoints
- `/search`: pass `include_usage` in the request body to echo per-search credit usage in the response.
- `/extract`: supports the same optional flag alongside your list of URLs.
- `/crawl` and `/map`: include the flag to retrieve crawl/map credit consumption.
### SDK usage
#### Python SDK
```python
from tavily import TavilyClient
client = TavilyClient(api_key="YOUR_TAVILY_API_KEY")
response = client.search(query="latest AI research", include_usage=True)
print(response["usage"])
```
#### JavaScript SDK
```javascript
import { TavilyClient } from "tavily";
const client = new TavilyClient({ apiKey: process.env.TAVILY_API_KEY });
const response = await client.search({ query: "agentic workflows", include_usage: true });
console.log(response.usage);
```
### MCP tools and integrations
- **Anthropic / Claude integrations**: when invoking `tavily-search`, `tavily-extract`, `tavily-crawl`, or `tavily-map`, include `"include_usage": true` in the tool arguments to receive usage data in the streamed response.
- **OpenAI Responses / Assistants API**: add `include_usage: true` to the Tavily tool arguments when creating tool calls so the returned messages contain the usage object.
## Remote MCP Server
Connect directly to Tavily's remote MCP server instead of running it locally. This provides a seamless experience without requiring local installation or configuration.
+68 -4
View File
@@ -16,6 +16,12 @@ if (!API_KEY) {
throw new Error("TAVILY_API_KEY environment variable is required");
}
type UsageValue = number | string | null | undefined;
interface UsageInfo {
total_credits?: UsageValue;
[key: string]: UsageValue;
}
interface TavilyResponse {
// Response structure from Tavily API
@@ -35,6 +41,7 @@ interface TavilyResponse {
raw_content?: string;
favicon?: string;
}>;
usage?: UsageInfo;
}
interface TavilyCrawlResponse {
@@ -45,12 +52,14 @@ interface TavilyCrawlResponse {
favicon?: string;
}>;
response_time: number;
usage?: UsageInfo;
}
interface TavilyMapResponse {
base_url: string;
results: string[];
response_time: number;
usage?: UsageInfo;
}
class TavilyClient {
@@ -204,6 +213,11 @@ class TavilyClient {
type: "boolean",
description: "Whether to include the favicon URL for each result",
default: false,
},
include_usage: {
type: "boolean",
description: "Whether to include credit usage information in the response. Credit usage may be reported as 0 until certain thresholds are reached.",
default: false,
}
},
required: ["query"]
@@ -242,6 +256,11 @@ class TavilyClient {
description: "Whether to include the favicon URL for each result",
default: false,
},
include_usage: {
type: "boolean",
description: "Whether to include credit usage information in the response. Credit usage may be reported as 0 until certain thresholds are reached.",
default: false,
}
},
required: ["urls"]
}
@@ -312,6 +331,11 @@ class TavilyClient {
description: "Whether to include the favicon URL for each result",
default: false,
},
include_usage: {
type: "boolean",
description: "Whether to include credit usage information in the response. Credit usage may be reported as 0 until certain thresholds are reached.",
default: false,
}
},
required: ["url"]
}
@@ -364,6 +388,11 @@ class TavilyClient {
type: "boolean",
description: "Whether to return external links in the final response",
default: true
},
include_usage: {
type: "boolean",
description: "Whether to include credit usage information in the response. Credit usage may be reported as 0 until certain thresholds are reached.",
default: false,
}
},
required: ["url"]
@@ -398,7 +427,8 @@ class TavilyClient {
include_domains: Array.isArray(args.include_domains) ? args.include_domains : [],
exclude_domains: Array.isArray(args.exclude_domains) ? args.exclude_domains : [],
country: args.country,
include_favicon: args.include_favicon
include_favicon: args.include_favicon,
include_usage: args.include_usage
});
break;
@@ -408,7 +438,8 @@ class TavilyClient {
extract_depth: args.extract_depth,
include_images: args.include_images,
format: args.format,
include_favicon: args.include_favicon
include_favicon: args.include_favicon,
include_usage: args.include_usage
});
break;
@@ -424,7 +455,8 @@ class TavilyClient {
allow_external: args.allow_external,
extract_depth: args.extract_depth,
format: args.format,
include_favicon: args.include_favicon
include_favicon: args.include_favicon,
include_usage: args.include_usage
});
return {
content: [{
@@ -442,7 +474,8 @@ class TavilyClient {
instructions: args.instructions,
select_paths: Array.isArray(args.select_paths) ? args.select_paths : [],
select_domains: Array.isArray(args.select_domains) ? args.select_domains : [],
allow_external: args.allow_external
allow_external: args.allow_external,
include_usage: args.include_usage
});
return {
content: [{
@@ -492,6 +525,7 @@ class TavilyClient {
const searchParams = {
...params,
include_usage: params?.include_usage ?? false,
api_key: API_KEY,
};
@@ -511,6 +545,7 @@ class TavilyClient {
try {
const response = await this.axiosInstance.post(this.baseURLs.extract, {
...params,
include_usage: params?.include_usage ?? false,
api_key: API_KEY
});
return response.data;
@@ -528,6 +563,7 @@ class TavilyClient {
try {
const response = await this.axiosInstance.post(this.baseURLs.crawl, {
...params,
include_usage: params?.include_usage ?? false,
api_key: API_KEY
});
return response.data;
@@ -545,6 +581,7 @@ class TavilyClient {
try {
const response = await this.axiosInstance.post(this.baseURLs.map, {
...params,
include_usage: params?.include_usage ?? false,
api_key: API_KEY
});
return response.data;
@@ -597,6 +634,8 @@ function formatResults(response: TavilyResponse): string {
});
}
appendUsage(output, response.usage);
return output.join('\n');
}
@@ -621,6 +660,8 @@ function formatCrawlResults(response: TavilyCrawlResponse): string {
}
});
appendUsage(output, response.usage);
return output.join('\n');
}
@@ -635,9 +676,32 @@ function formatMapResults(response: TavilyMapResponse): string {
output.push(`\n[${index + 1}] URL: ${page}`);
});
appendUsage(output, response.usage);
return output.join('\n');
}
function appendUsage(output: string[], usage?: UsageInfo): void {
if (!usage) {
return;
}
const entries = Object.entries(usage).filter(([, value]) => value !== undefined && value !== null);
if (!entries.length) {
return;
}
output.push('\nUsage:');
for (const [key, value] of entries) {
output.push(`${formatUsageKey(key)}: ${value}`);
}
}
function formatUsageKey(key: string): string {
return key.replace(/_/g, ' ');
}
function listTools(): void {
const tools = [
{