Skip to main content
Glama
moma1992

Yaizu Smart City MCP Server

by moma1992

scrape_api_docs

Extract and save API documentation from Yaizu City's API catalog for municipal services and smart city data access.

Instructions

焼津市APIカタログから最新のAPIドキュメントをスクレイピングして保存します。 認証情報は.envファイルから自動的に読み込まれます。

Returns: str: スクレイピング結果のサマリー

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Primary handler function for the 'scrape_api_docs' MCP tool. Decorated with @mcp.tool() for registration. Orchestrates scraping by initializing the scraper via doc_manager and calling scrape_and_save_all(), then returns a formatted summary.
    @mcp.tool()
    async def scrape_api_docs() -> str:
        """
        焼津市APIカタログから最新のAPIドキュメントをスクレイピングして保存します。
        認証情報は.envファイルから自動的に読み込まれます。
        
        Returns:
            str: スクレイピング結果のサマリー
        """
        try:
            scraper = await doc_manager.initialize_scraper()
            
            # スクレイピングと保存を実行
            result = await scraper.scrape_and_save_all()
            
            if result['success']:
                summary = f"""# スクレイピング完了
    
    ## 結果サマリー
    - **総API数**: {result['total_apis']}
    - **防災関連API数**: {result['disaster_apis']}
    - **保存されたファイル数**: {len(result['saved_files'])}
    
    ## 保存されたファイル
    """
                for filename in result['saved_files']:
                    summary += f"- {filename}\n"
                
                summary += "\n✅ APIドキュメントの更新が完了しました。"
                return summary
            else:
                return "❌ スクレイピングに失敗しました。認証情報を確認してください。"
                
        except Exception as e:
            logger.error(f"スクレイピングエラー: {e}")
            return f"❌ エラーが発生しました: {str(e)}"
  • Core helper method in YaizuAPIScraper class that performs the actual scraping: logs in, fetches full API catalog, extracts disaster-related APIs, saves multiple JSON files locally, and returns summary statistics.
    async def scrape_and_save_all(self) -> Dict[str, Any]:
        """すべてのAPIデータをスクレイピングして保存"""
        result = {
            'success': False,
            'total_apis': 0,
            'disaster_apis': 0,
            'saved_files': []
        }
        
        # ログイン
        if not await self.login():
            logger.error("ログインに失敗しました")
            return result
        
        # APIカタログを取得
        catalog = await self.fetch_api_catalog()
        if catalog:
            # 全体のカタログを保存
            if await self.save_api_data(catalog, 'api_catalog'):
                result['saved_files'].append('api_catalog.json')
            
            result['total_apis'] = len(catalog.get('apis', []))
        
        # 防災関連APIを取得
        disaster_apis = await self.fetch_disaster_apis()
        if disaster_apis:
            disaster_catalog = {
                'title': '焼津市防災関連API',
                'apis': disaster_apis,
                'last_updated': datetime.now().isoformat()
            }
            
            if await self.save_api_data(disaster_catalog, 'disaster_apis'):
                result['saved_files'].append('disaster_apis.json')
            
            result['disaster_apis'] = len(disaster_apis)
            
            # 個別のAPI詳細も保存
            for api in disaster_apis:
                api_name = api.get('name', 'unknown').replace(' ', '_').replace('/', '_')
                if await self.save_api_data(api, f"api_{api_name}"):
                    result['saved_files'].append(f"api_{api_name}.json")
        
        result['success'] = True
        logger.info(f"スクレイピング完了: {result}")
        
        return result
  • APIDocumentManager class provides document management, scraper initialization (key for tool), loading/saving/searching of scraped API docs. Global instance doc_manager used in handler.
    class APIDocumentManager:
        """APIドキュメント管理クラス"""
        
        def __init__(self):
            self.data_dir = Path("data/api_specs")
            self.api_docs_dir = Path("data/api_specs")
            self.data_dir.mkdir(parents=True, exist_ok=True)
            self.api_docs_dir.mkdir(parents=True, exist_ok=True)
            self.scraper = None
        
        async def initialize_scraper(self) -> YaizuAPIScraper:
            """スクレイパーの初期化"""
            if not self.scraper:
                self.scraper = YaizuAPIScraper()
                await self.scraper.__aenter__()
            return self.scraper
        
        async def cleanup(self):
            """リソースのクリーンアップ"""
            if self.scraper:
                await self.scraper.__aexit__(None, None, None)
        
        def load_api_docs(self, filename: str = "api_catalog") -> Optional[Dict[str, Any]]:
            """保存済みのAPIドキュメントを読み込む"""
            try:
                # data/api_specsディレクトリを確認
                specs_filepath = self.data_dir / f"{filename}.json"
                if specs_filepath.exists():
                    with open(specs_filepath, 'r', encoding='utf-8') as f:
                        return json.load(f)
                data_filepath = self.data_dir / f"{filename}.json"
                if data_filepath.exists():
                    with open(data_filepath, 'r', encoding='utf-8') as f:
                        return json.load(f)
                
                logger.warning(f"APIドキュメントが見つかりません: {filename}")
                return None
                    
            except Exception as e:
                logger.error(f"APIドキュメント読み込みエラー: {e}")
                return None
        
        def list_available_docs(self) -> List[str]:
            """利用可能なドキュメントファイルの一覧"""
            try:
                files = set()
                # data/api_specsディレクトリのファイル
                if self.data_dir.exists():
                    files.update(f.stem for f in self.data_dir.glob('*.json'))
                return sorted(list(files))
            except Exception as e:
                logger.error(f"ドキュメント一覧取得エラー: {e}")
                return []
        
        def search_apis(self, keyword: str) -> List[Dict[str, Any]]:
            """キーワードでAPIを検索"""
            results = []
            
            # すべてのドキュメントを検索
            for doc_file in self.list_available_docs():
                doc = self.load_api_docs(doc_file)
                if not doc:
                    continue
                
                # APIs配列がある場合
                if 'apis' in doc:
                    for api in doc['apis']:
                        # 名前と説明で検索
                        if (keyword.lower() in api.get('name', '').lower() or 
                            keyword.lower() in api.get('description', '').lower() or
                            keyword.lower() in api.get('category', '').lower()):
                            results.append({
                                'source_file': doc_file,
                                'api': api
                            })
            
            return results
Behavior3/5

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

With no annotations provided, the description carries the full burden. It discloses that authentication is handled via .env files and that it saves the scraped data, which are useful behavioral traits. However, it lacks details on rate limits, error handling, or what 'saves' entails (e.g., file location, overwrite behavior).

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

Conciseness4/5

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

The description is brief and front-loaded with the main action in the first sentence. The second sentence adds useful authentication context, and the 'Returns' section clarifies output. It could be slightly more structured but avoids waste.

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

Completeness3/5

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

Given no annotations, 0 parameters, and an output schema (implied by 'Returns'), the description is minimally adequate. It covers the action and authentication, but lacks context on sibling tool differentiation and detailed behavioral aspects like what 'saves' means, leaving some gaps.

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

Parameters4/5

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

The input schema has 0 parameters with 100% coverage, so no parameter documentation is needed. The description appropriately doesn't discuss parameters, earning a baseline score of 4 for not adding unnecessary information.

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 tool scrapes API documentation from a specific source (Yaizu City API catalog) and saves it, using the verb 'scrape' and resource 'API documentation'. However, it doesn't explicitly differentiate from sibling tools like 'search_api_docs' or 'get_api_details', which might have overlapping functionality.

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 'search_api_docs' or 'get_api_details'. It mentions authentication is handled automatically, but doesn't specify prerequisites, timing, or exclusions for usage.

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/moma1992/smartcity-mcp'

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