search_bonds
Search corporate bonds by ticker, seniority, yield, and maturity to identify high-yield opportunities or analyze maturity walls using real-time credit data.
Instructions
Search bonds by ticker, seniority, yield, spread, and maturity. Use for yield hunting, finding high-yield opportunities, or analyzing maturity walls. Example: 'Find senior unsecured bonds yielding above 8%'
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| ticker | No | Company ticker(s) | |
| seniority | No | Bond seniority level | |
| min_ytm | No | Minimum yield to maturity (%) | |
| has_pricing | No | Only bonds with pricing data | |
| maturity_before | No | Maturity before date (YYYY-MM-DD) | |
| limit | No | Maximum results (default 10) |
Implementation Reference
- debtstack/mcp_server.py:239-277 (registration)MCP tool registration for 'search_bonds' - defines the tool name, description, and input schema with parameters like ticker, seniority, min_ytm, has_pricing, maturity_before, and limit
Tool( name="search_bonds", description=( "Search bonds by ticker, seniority, yield, spread, and maturity. " "Use for yield hunting, finding high-yield opportunities, or analyzing maturity walls. " "Example: 'Find senior unsecured bonds yielding above 8%'" ), inputSchema={ "type": "object", "properties": { "ticker": { "type": "string", "description": "Company ticker(s)" }, "seniority": { "type": "string", "enum": ["senior_secured", "senior_unsecured", "subordinated"], "description": "Bond seniority level" }, "min_ytm": { "type": "number", "description": "Minimum yield to maturity (%)" }, "has_pricing": { "type": "boolean", "description": "Only bonds with pricing data" }, "maturity_before": { "type": "string", "description": "Maturity before date (YYYY-MM-DD)" }, "limit": { "type": "integer", "description": "Maximum results (default 10)" } }, "required": [] } ), - debtstack/mcp_server.py:436-447 (handler)MCP tool handler that executes search_bonds - processes arguments, makes API call to /bonds endpoint, formats results using format_bond helper, and returns formatted text
elif name == "search_bonds": params = {k: v for k, v in arguments.items() if v is not None} params.setdefault("limit", 10) result = api_get("/bonds", params) bonds = result.get("data", []) if not bonds: return [TextContent(type="text", text="No bonds found matching criteria.")] text = f"Found {len(bonds)} bonds:\n\n" text += "\n\n---\n\n".join(format_bond(b) for b in bonds) return [TextContent(type="text", text=text)] - debtstack/client.py:194-319 (handler)Core async implementation of search_bonds - builds parameters from filters (ticker, seniority, min_ytm, max_ytm, spread, maturity, etc.), makes HTTP GET request to /bonds endpoint, returns JSON response with bond data
async def search_bonds( self, ticker: Optional[str] = None, cusip: Optional[str] = None, sector: Optional[str] = None, seniority: Optional[str] = None, security_type: Optional[str] = None, instrument_type: Optional[str] = None, issuer_type: Optional[str] = None, rate_type: Optional[str] = None, min_coupon: Optional[float] = None, max_coupon: Optional[float] = None, min_ytm: Optional[float] = None, max_ytm: Optional[float] = None, min_spread: Optional[int] = None, max_spread: Optional[int] = None, maturity_before: Optional[Union[str, date]] = None, maturity_after: Optional[Union[str, date]] = None, min_outstanding: Optional[int] = None, has_pricing: Optional[bool] = None, has_guarantors: Optional[bool] = None, has_cusip: Optional[bool] = None, currency: Optional[str] = None, fields: Optional[str] = None, sort: str = "name", limit: int = 50, offset: int = 0, ) -> Dict[str, Any]: """ Search bonds with powerful filtering for yield hunting and screening. Args: ticker: Filter by company ticker(s) cusip: Filter by CUSIP(s) sector: Filter by company sector seniority: senior_secured, senior_unsecured, subordinated security_type: first_lien, second_lien, unsecured instrument_type: term_loan_b, senior_notes, revolver, etc. issuer_type: holdco, opco, subsidiary rate_type: fixed, floating min_coupon: Minimum coupon rate (%) max_coupon: Maximum coupon rate (%) min_ytm: Minimum yield to maturity (%) max_ytm: Maximum yield to maturity (%) min_spread: Minimum spread to treasury (bps) max_spread: Maximum spread to treasury (bps) maturity_before: Maturity before date maturity_after: Maturity after date min_outstanding: Minimum outstanding (cents) has_pricing: Has pricing data has_guarantors: Has guarantor entities has_cusip: Has CUSIP (tradeable) currency: Currency code (e.g., "USD") fields: Comma-separated fields to return sort: Sort field, prefix with - for descending limit: Results per page (max 100) offset: Pagination offset Returns: Dictionary with "data" (list of bonds) and "meta" (pagination info) Example: # Find high-yield bonds yielding >8% result = await client.search_bonds( seniority="senior_unsecured", min_ytm=8.0, has_pricing=True, fields="name,cusip,company_ticker,coupon_rate,maturity_date,pricing", sort="-pricing.ytm" ) """ params = { "sort": sort, "limit": limit, "offset": offset, } if ticker: params["ticker"] = ticker if cusip: params["cusip"] = cusip if sector: params["sector"] = sector if seniority: params["seniority"] = seniority if security_type: params["security_type"] = security_type if instrument_type: params["instrument_type"] = instrument_type if issuer_type: params["issuer_type"] = issuer_type if rate_type: params["rate_type"] = rate_type if min_coupon is not None: params["min_coupon"] = min_coupon if max_coupon is not None: params["max_coupon"] = max_coupon if min_ytm is not None: params["min_ytm"] = min_ytm if max_ytm is not None: params["max_ytm"] = max_ytm if min_spread is not None: params["min_spread"] = min_spread if max_spread is not None: params["max_spread"] = max_spread if maturity_before: params["maturity_before"] = str(maturity_before) if maturity_after: params["maturity_after"] = str(maturity_after) if min_outstanding is not None: params["min_outstanding"] = min_outstanding if has_pricing is not None: params["has_pricing"] = has_pricing if has_guarantors is not None: params["has_guarantors"] = has_guarantors if has_cusip is not None: params["has_cusip"] = has_cusip if currency: params["currency"] = currency if fields: params["fields"] = fields client = await self._get_client() response = await client.get("/bonds", params=params) response.raise_for_status() return response.json() - debtstack/client.py:760-764 (handler)Synchronous wrapper for search_bonds in DebtStack class - wraps async implementation in synchronous interface using _run helper
def search_bonds(self, **kwargs) -> Dict[str, Any]: async def _call(): async with DebtStackClient(self.api_key, **self.kwargs) as client: return await client.search_bonds(**kwargs) return self._run(_call()) - debtstack/langchain.py:154-190 (schema)LangChain input schema (SearchBondsInput) - defines Pydantic BaseModel with fields for ticker, seniority, min_ytm, max_ytm, min_spread, has_pricing, and maturity parameters
class SearchBondsInput(BaseModel): """Input for bond search tool.""" ticker: Optional[str] = Field( None, description="Company ticker(s) to filter by" ) seniority: Optional[str] = Field( None, description="Seniority level: 'senior_secured', 'senior_unsecured', 'subordinated'" ) min_ytm: Optional[float] = Field( None, description="Minimum yield to maturity (%)" ) max_ytm: Optional[float] = Field( None, description="Maximum yield to maturity (%)" ) min_spread: Optional[int] = Field( None, description="Minimum spread to treasury (basis points)" ) has_pricing: Optional[bool] = Field( None, description="Filter for bonds with pricing data" ) maturity_before: Optional[str] = Field( None, description="Maturity before date (YYYY-MM-DD)" ) maturity_after: Optional[str] = Field( None, description="Maturity after date (YYYY-MM-DD)" ) fields: Optional[str] = Field( None, description="Comma-separated fields to return"