Skip to main content
Glama
clsung

Taiwan Stock Agent

by clsung

get_stock_data

Retrieve detailed stock information for Taiwan-listed companies, including real-time prices, historical data, company details, and technical analysis to support investment decisions.

Instructions

Get detailed information about a specific stock.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
stock_codeYes

Implementation Reference

  • Core handler function that validates the stock code, fetches data from StockService, and formats the response for MCP.
    @mcp_error_handler("get_stock_data")
    async def get_stock_data(stock_code: str) -> dict[str, Any]:
        """
        取得股票基本資料
        
        Args:
            stock_code: 股票代號,例如:2330
            
        Returns:
            股票資料,包含公司概況、產業別、市值等資訊
            
        Raises:
            InvalidStockCodeError: 股票代號格式錯誤
            StockNotFoundError: 找不到股票
            StockDataUnavailableError: 股票資料無法取得
        """
        # Validate request parameters
        validated_params = validate_stock_request(stock_code=stock_code)
        
        # Fetch stock data using the validated stock code
        result = await stock_service.fetch_stock_data(validated_params["stock_code"])
        
        # Format response for MCP
        return MCPResponseFormatter.format_stock_data_response(result)
  • mcp_server.py:77-102 (registration)
    MCP tool registration for 'get_stock_data' with input stock_code: str and output StockDataResponse. Delegates to core handler and handles errors.
    @mcp.tool(name="get_stock_data",
              description="Get detailed information about a specific stock.",
    )
    async def get_stock_data_tool(stock_code: str) -> StockDataResponse:
        """Get detailed information about a specific stock."""
        try:
            raw_data = await get_stock_data(stock_code)
            # Extract clean data without _metadata for Pydantic model
            from tw_stock_agent.utils.mcp_error_handler import MCPResponseFormatter
            clean_data = MCPResponseFormatter.extract_metadata_for_model(raw_data)
            return StockDataResponse(**clean_data)
        except TwStockAgentError as e:
            # For MCP tools, we need to return a valid response with error information
            return StockDataResponse(
                stock_code=stock_code,
                updated_at=e.context.timestamp.isoformat(),
                error=e.message
            )
        except Exception as e:
            # Handle unexpected errors
            return StockDataResponse(
                stock_code=stock_code,
                updated_at=datetime.now().isoformat(),
                error=f"Unexpected error: {str(e)}"
            )
  • Pydantic schema for the tool's output, defining structure, validation, and computed fields for stock data responses.
    class StockDataResponse(BaseStockResponse):
        """Enhanced response model for stock basic data."""
        
        name: Optional[str] = Field(
            None,
            description="Company name (公司名稱)",
            example="台積電",
            alias="companyName"
        )
        name_en: Optional[str] = Field(
            None,
            description="English company name",
            alias="companyNameEn"
        )
        stock_type: Optional[str] = Field(
            None,
            description="Stock type (股票類型)",
            example="股票",
            alias="type"
        )
        isin_code: Optional[str] = Field(
            None,
            description="ISIN code (ISIN代碼)",
            alias="isin"
        )
        listing_date: Optional[datetime] = Field(
            None,
            description="Listing date (上市日期)",
            alias="startDate"
        )
        market_type: Optional[str] = Field(
            None,
            description="Market type (市場別)",
            example="上市",
            alias="market"
        )
        industry_category: Optional[str] = Field(
            None,
            description="Industry category (產業別)",
            example="半導體業",
            alias="industry"
        )
        market_cap: Optional[TWDAmount] = Field(
            None,
            description="Market capitalization",
            alias="marketCap"
        )
        
        def __init__(self, **data):
            # Handle backward compatibility for field names
            if 'type' in data and 'stock_type' not in data:
                data['stock_type'] = data.pop('type')
            if 'start_date' in data and 'listing_date' not in data:
                start_date = data.pop('start_date')
                if start_date:
                    try:
                        data['listing_date'] = datetime.fromisoformat(start_date.replace('Z', '+00:00'))
                    except (ValueError, AttributeError):
                        pass
            
            super().__init__(**data)
        
        @field_validator("listing_date")
        @classmethod
        def validate_listing_date(cls, v: Optional[Union[str, datetime]]) -> Optional[datetime]:
            """Validate and convert listing date."""
            if v is None:
                return None
            
            if isinstance(v, str):
                try:
                    # Handle various date formats
                    if 'T' in v:  # ISO format
                        return datetime.fromisoformat(v.replace('Z', '+00:00')).astimezone(TAIWAN_TZ)
                    else:  # Date only
                        return datetime.strptime(v, '%Y-%m-%d').replace(tzinfo=TAIWAN_TZ)
                except ValueError as e:
                    raise ValueError(f"Invalid date format: {v}") from e
            
            return v.astimezone(TAIWAN_TZ) if v.tzinfo else v.replace(tzinfo=TAIWAN_TZ)
        
        @computed_field
        @property
        def years_listed(self) -> Optional[int]:
            """Calculate years since listing."""
            if not self.listing_date:
                return None
            
            years = (datetime.now(TAIWAN_TZ) - self.listing_date).days // 365
            return max(0, years)
        
        @computed_field
        @property
        def is_recently_listed(self) -> bool:
            """Check if stock was listed within the last year."""
            if not self.listing_date:
                return False
            
            days_since_listing = (datetime.now(TAIWAN_TZ) - self.listing_date).days
            return days_since_listing <= 365
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It states the action ('Get') but doesn't clarify if this is a read-only operation, requires authentication, has rate limits, or what the output format might be. For a tool with zero annotation coverage, this leaves significant gaps in understanding its behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that directly states the tool's purpose without unnecessary words. It's appropriately sized and front-loaded, making it easy to parse quickly, though it could benefit from more detail given the lack of other documentation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of financial data tools, no annotations, no output schema, and low schema coverage, the description is incomplete. It doesn't address what 'detailed information' includes, how results are returned, or any prerequisites, making it inadequate for an agent to use this tool effectively without additional context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 0%, and the description doesn't add any meaning beyond the input schema. It mentions 'a specific stock' but doesn't explain what 'stock_code' represents (e.g., ticker symbol, format examples like 'AAPL' or 'GOOGL'), leaving the parameter semantics unclear and undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb ('Get') and resource ('detailed information about a specific stock'), making the purpose understandable. However, it doesn't distinguish this tool from potential siblings like 'get_realtime_data' or 'get_price_history', which might also provide stock information with different scopes or formats.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like 'get_realtime_data' or 'get_price_history'. It lacks context about what makes this tool unique, such as whether it returns comprehensive data, real-time updates, or historical trends, leaving the agent to guess based on tool names alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/clsung/tw-stock-agent'

If you have feedback or need assistance with the MCP directory API, please join our Discord server