get_rate
Retrieve the official Bank of Russia exchange rate for a specified currency, optionally on a given date. Returns nominal, per-unit rate, and value.
Instructions
Get the official Bank of Russia exchange rate for a single currency on a given date (or the latest published date if 'on_date' is omitted). Returns nominal, value, per-unit rate and effective quote date.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| char_code | Yes | ||
| on_date | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| char_code | Yes | ISO-letter code, e.g. 'USD'. | |
| num_code | Yes | Numeric ISO 4217 code as string, e.g. '840'. | |
| name | Yes | Russian-language currency name from CBR. | |
| nominal | Yes | Number of foreign units the rate is given for. | |
| value | Yes | Rate of <nominal> units in RUB. | |
| vunit_rate | Yes | Rate per single unit (value / nominal). | |
| date | Yes | Effective quote date as published by CBR. | |
| source | No | Центральный банк РФ |
Implementation Reference
- src/mcp_cbr_rates/tools.py:63-101 (handler)The core handler function for the get_rate tool. Fetches a single currency rate from CBR (with caching), parses the response, and returns a CurrencyRate model.
async def get_rate( ctx: ToolContext, char_code: str, on_date: date | str | None = None, ) -> CurrencyRate: """Fetch the CBR quote for a single currency on the given (or latest) date.""" canonical = normalize_char_code(char_code) target_date = _coerce_date(on_date) cache_key = f"daily:{canonical}:{target_date.isoformat() if target_date else 'latest'}" cached = await ctx.daily_cache.get(cache_key) if cached is not None: return cached # type: ignore[no-any-return] raw = await ctx.client.fetch_currency_rate(canonical, on_date=target_date) nominal = int(raw.get("nominal") or 1) value = _decimal(raw["value"]) vunit_text = raw.get("vunit_rate") or "" if vunit_text: vunit = _decimal(vunit_text) else: vunit = (value / nominal) if nominal else value quote_date = ( date.fromisoformat(_iso_from_dotted(raw["date"])) if raw.get("date") else (target_date or date.today()) ) rate = CurrencyRate( char_code=canonical, num_code=raw.get("num_code", ""), name=raw.get("name", ""), nominal=nominal, value=value, vunit_rate=vunit, date=quote_date, ) await ctx.daily_cache.set(cache_key, rate, ttl=DEFAULT_DAILY_TTL) return rate - src/mcp_cbr_rates/server.py:170-186 (registration)Registration of the get_rate MCP tool via FastMCP @mcp.tool decorator. Maps the MCP tool name 'get_rate' to the handler function tool_get_rate, which delegates to _get_rate (the tools.get_rate implementation).
@mcp.tool( name="get_rate", description=( "Get the official Bank of Russia exchange rate for a single currency" " on a given date (or the latest published date if 'on_date' is omitted)." " Returns nominal, value, per-unit rate and effective quote date." ), ) async def tool_get_rate( ctx: Context, char_code: str, on_date: date | None = None, ) -> CurrencyRate: try: return await _get_rate(_ctx(ctx), char_code=char_code, on_date=on_date) except CbrError as exc: raise RuntimeError(_format_error(exc)) from exc - src/mcp_cbr_rates/tools.py:47-62 (helper)Helper function _coerce_date used by get_rate to accept date or ISO string input for the on_date parameter.
def _coerce_date(value: date | str | None) -> date | None: """Accept either a ``date`` or an ISO ``YYYY-MM-DD`` string.""" if value is None or isinstance(value, date): return value if isinstance(value, str): try: return date.fromisoformat(value) except ValueError as exc: raise CbrValidationError(f"invalid ISO date: {value!r}") from exc raise CbrValidationError(f"unsupported date value: {value!r}") def _decimal(text: str) -> Decimal: return Decimal(text.replace(",", ".").strip()) - src/mcp_cbr_rates/tools.py:55-67 (helper)Helper function normalize_char_code from currency_codes.py — used to validate and canonicalize currency code input.
raise CbrValidationError(f"invalid ISO date: {value!r}") from exc raise CbrValidationError(f"unsupported date value: {value!r}") def _decimal(text: str) -> Decimal: return Decimal(text.replace(",", ".").strip()) async def get_rate( ctx: ToolContext, char_code: str, on_date: date | str | None = None, ) -> CurrencyRate: - src/mcp_cbr_rates/schemas.py:27-37 (schema)The CurrencyRate Pydantic model returned by get_rate, defining fields like char_code, num_code, name, nominal, value, vunit_rate, and date.
class CurrencyRate(CbrModel): """A single currency quote at a given date.""" char_code: str = Field(..., description="ISO-letter code, e.g. 'USD'.") num_code: str = Field(..., description="Numeric ISO 4217 code as string, e.g. '840'.") name: str = Field(..., description="Russian-language currency name from CBR.") nominal: int = Field(..., ge=1, description="Number of foreign units the rate is given for.") value: Decimal = Field(..., description="Rate of <nominal> units in RUB.") vunit_rate: Decimal = Field(..., description="Rate per single unit (value / nominal).") date: _dt.date = Field(..., description="Effective quote date as published by CBR.") source: str = DEFAULT_SOURCE