Skip to main content
Glama

refresh_cache

Refresh cached policy documents from the ASF website by re-fetching them in parallel, bypassing the 30-day cache.

Instructions

Re-fetch policy documents from the ASF website in parallel, bypassing the 30-day cache.

Omit keys to refresh all policies.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
keysNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The `refresh_cache` tool handler function. It takes an optional list of policy keys, loads the existing cache from disk, fetches each policy's text from the ASF website in parallel using a ThreadPoolExecutor with 8 workers, updates the in-memory cache dict, and persists it back to disk. Returns a summary of refreshed policies and any errors.
    def refresh_cache(keys: list[str] | None = None) -> str:
        """Re-fetch policy documents from the ASF website in parallel, bypassing the 30-day cache.
    
        Omit keys to refresh all policies.
        """
        unknown = [k for k in (keys or []) if k not in POLICY_SOURCES]
        targets = [k for k in (keys or list(POLICY_SOURCES.keys())) if k in POLICY_SOURCES]
    
        # Load once; each worker writes its own entry then we merge and save once at the end
        cache = fetcher.load_cache()
    
        def fetch_one(key: str) -> tuple[str, str]:
            text = fetcher.fetch_page_text(POLICY_SOURCES[key]["url"])
            return key, text
    
        refreshed: list[str] = []
        errors: list[str] = [f"Unknown key: `{k}`" for k in unknown]
    
        with ThreadPoolExecutor(max_workers=8) as pool:
            futures = {pool.submit(fetch_one, k): k for k in targets}
            for future in as_completed(futures):
                key, text = future.result()
                if text.startswith("[Error"):
                    errors.append(f"{key}: {text}")
                else:
                    cache[key] = {"text": text, "fetched_at": time.time(), "url": POLICY_SOURCES[key]["url"]}
                    refreshed.append(key)
    
        fetcher.save_cache(cache)
    
        msg = f"Refreshed {len(refreshed)} policies: {', '.join(sorted(refreshed))}"
        if errors:
            msg += "\n\nErrors:\n" + "\n".join(errors)
        return msg
  • The `@mcp.tool()` decorator on `refresh_cache` registers it as a FastMCP tool. The `mcp` instance is created at line 14 and run from server.py.
    @mcp.tool()
  • `fetch_page_text` is the helper called by `refresh_cache`'s inner `fetch_one` to download the HTML and convert it to plain text.
    def fetch_page_text(url: str) -> str:
        """Fetch *url* and return its content as plain text, or an error string."""
        try:
            with httpx.Client(follow_redirects=True, timeout=30) as client:
                resp = client.get(url, headers={"User-Agent": "asf-policy-mcp/0.1.0"})
                resp.raise_for_status()
            return html_to_text(resp.text)
        except Exception as exc:
            return f"[Error fetching {url}: {exc}]"
  • `save_cache` is called by `refresh_cache` after all fetches complete to persist the updated cache dict to disk.
    def save_cache(cache: dict[str, Any]) -> None:
        """Persist the cache dict to disk, creating parent directories as needed."""
        CACHE_FILE.parent.mkdir(parents=True, exist_ok=True)
        CACHE_FILE.write_text(json.dumps(cache, indent=2), encoding="utf-8")
  • `POLICY_SOURCES` is the schema/registry of valid policy keys, used by `refresh_cache` to validate keys and look up URLs.
    POLICY_SOURCES: dict[str, dict[str, str]] = {
        "pmc": {
            "title": "PMC Guide (Mailing Lists, Committers, PMC Members)",
            "url": "https://www.apache.org/dev/pmc.html",
            "section": "Community And Project Oversight",
            "description": "Rules for mailing lists, adding committers, and managing PMC membership",
        },
        "project_independence": {
            "title": "Project Independence",
            "url": "https://community.apache.org/projectIndependence.html",
            "section": "Independence",
            "description": "Guidelines for operating independently and for the public good",
        },
        "board_reporting": {
            "title": "Board Reporting Requirements",
            "url": "https://www.apache.org/foundation/board/reporting",
            "section": "Reporting",
            "description": "Quarterly board status report requirements for PMCs",
        },
        "release_policy": {
            "title": "Release Policy",
            "url": "https://www.apache.org/legal/release-policy",
            "section": "Release",
            "description": "Apache software release policy - what constitutes a valid release",
        },
        "voting": {
            "title": "Apache Voting Process",
            "url": "https://www.apache.org/foundation/voting.html",
            "section": "Release",
            "description": "Apache voting process for releases and other decisions",
        },
        "release_distribution": {
            "title": "Release Distribution Policy",
            "url": "https://www.apache.org/dev/release-distribution",
            "section": "Release",
            "description": "Policy for how and where Apache releases are distributed",
        },
        "security": {
            "title": "Security Team Guidance",
            "url": "https://www.apache.org/security/",
            "section": "Security",
            "description": "Security notification and disclosure procedures",
        },
        "security_committers": {
            "title": "Vulnerability Handling for Committers",
            "url": "https://www.apache.org/security/committers.html",
            "section": "Security",
            "description": "How committers should handle reported security vulnerabilities",
        },
        "licenses": {
            "title": "Contributor License Agreements (CLAs)",
            "url": "https://www.apache.org/licenses/",
            "section": "Licensing",
            "description": "CLA requirements and Apache license versions",
        },
        "source_headers": {
            "title": "Apache Source Headers",
            "url": "https://www.apache.org/legal/src-headers.html",
            "section": "Licensing",
            "description": "Required Apache license headers in source files",
        },
        "resolved_licenses": {
            "title": "Approved/Resolved Third-Party Licenses",
            "url": "https://www.apache.org/legal/resolved.html",
            "section": "Licensing",
            "description": "Which third-party licenses are Category A (allowed), B (limited), or X (forbidden)",
        },
        "branding": {
            "title": "Project Branding Requirements",
            "url": "https://www.apache.org/foundation/marks/pmcs",
            "section": "Branding",
            "description": "Trademark and branding requirements for PMC projects",
        },
        "trademark_maintenance": {
            "title": "Trademark Maintenance Responsibilities",
            "url": "https://www.apache.org/foundation/marks/responsibility.html",
            "section": "Branding",
            "description": "PMC responsibilities for maintaining Apache trademarks",
        },
        "website_linking": {
            "title": "Website Linking Policy",
            "url": "https://www.apache.org/foundation/marks/linking",
            "section": "Branding",
            "description": "Policy on linking to and from Apache project websites",
        },
        "repo_policy": {
            "title": "Repository Policy",
            "url": "https://infra.apache.org/project-repo-policy.html",
            "section": "Infrastructure",
            "description": "Policy for project source code repositories",
        },
        "website_policy": {
            "title": "Website Policy",
            "url": "https://infra.apache.org/project-site-policy.html",
            "section": "Infrastructure",
            "description": "Policy for project websites and hosting",
        },
        "press": {
            "title": "Press & Marketing Policy",
            "url": "https://www.apache.org/press/",
            "section": "Press",
            "description": "Guidelines for press releases and marketing coordination",
        },
        "sponsorship": {
            "title": "Sponsorship Requirements",
            "url": "https://www.apache.org/foundation/sponsorship.html",
            "section": "Fundraising",
            "description": "Fundraising and sponsorship policies",
        },
        "privacy": {
            "title": "Privacy Policy",
            "url": "https://privacy.apache.org/policies/privacy-policy-public.html",
            "section": "Privacy",
            "description": "ASF privacy policy",
        },
        "incubator": {
            "title": "Incubator Podling Policies",
            "url": "https://incubator.apache.org/policy/incubation.html",
            "section": "Incubator",
            "description": "Policies governing Apache Incubator podlings",
        },
    }
Behavior3/5

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

The description mentions parallel fetching and cache bypass, which are key traits. But without annotations, it should disclose potential costs (external fetches) and safety (non-destructive but mutates cache). Currently lacks these.

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?

Two sentences with no redundancy. The first sentence states the main action, the second explains the parameter behavior. Efficient and well-structured.

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

Completeness4/5

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

With an output schema and a single optional parameter, the description covers the essential information for invocation. Minor gap: doesn't mention the effect on other tools' data (e.g., get_policy will now show fresh data).

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 only parameter 'keys' has no schema description, but the description clarifies its meaning: omit to refresh all, provide to refresh specific. This adds value beyond the schema.

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

Purpose5/5

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

The description clearly states the action (re-fetch policy documents via parallel) and resource (ASF website), and it distinguishes from sibling tools that read the cached policies.

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

Usage Guidelines4/5

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

It explains when to use the tool (to bypass cache and force refresh) and how to scope the refresh (omit keys for all, provide keys for specific). However, no explicit 'when not to use' or alternatives.

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/justinmclean/PolicyMCP'

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