Skip to main content
Glama
philipithomas

Contraption Company MCP

Official

fetch

Retrieve specific blog posts from Contraption Company by providing an identifier such as a slug, URL, or post ID.

Instructions

Fetch a blog post using the MCP HTTP-style contract.

Accepts an id that can be a slug, canonical URL, or a post:// style identifier.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
idYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The handler function for the 'fetch' tool. It validates the input id, extracts the post slug, retrieves the post data and markdown from ChromaService, resolves a canonical URL, and returns an HTTP-like response dictionary with the post details.
    @mcp.tool(name="fetch")
    async def fetch(id: str) -> dict[str, Any]:
        """Fetch a blog post using the MCP HTTP-style contract.
    
        Accepts an ``id`` that can be a slug, canonical URL, or a ``post://`` style identifier.
        """
    
        if not id:
            return {
                "status": {"code": 400, "text": "Bad Request"},
                "headers": {"Content-Type": "application/json"},
                "body": {
                    "kind": "text",
                    "text": json.dumps({"error": "An 'id' must be provided"}),
                },
            }
    
        slug = _extract_slug_from_url(id)
        if not slug:
            return {
                "status": {"code": 400, "text": "Bad Request"},
                "headers": {"Content-Type": "application/json"},
                "body": {
                    "kind": "text",
                    "text": json.dumps({"error": "Unable to determine post slug from identifier"}),
                },
            }
    
        chroma_service = await get_chroma_service()
        post_summary, markdown = await chroma_service.get_post_markdown(slug)
    
        if not post_summary or markdown is None:
            return {
                "status": {"code": 404, "text": "Not Found"},
                "headers": {"Content-Type": "application/json"},
                "body": {
                    "kind": "text",
                    "text": json.dumps({"error": "Post not found"}),
                },
            }
    
        resolved_url = _canonical_post_url(post_summary, id)
        if not resolved_url:
            logger.warning("Unable to resolve canonical URL for post %s", post_summary.id)
            return {
                "status": {"code": 502, "text": "Bad Gateway"},
                "headers": {"Content-Type": "application/json"},
                "body": {
                    "kind": "text",
                    "text": json.dumps({"error": "Unable to resolve canonical URL for post"}),
                },
            }
    
        response_body = {
            "id": resolved_url,
            "title": post_summary.title,
            "excerpt": post_summary.excerpt,
            "url": resolved_url,
            "published_at": post_summary.published_at.isoformat()
            if post_summary.published_at
            else None,
            "updated_at": post_summary.updated_at.isoformat() if post_summary.updated_at else None,
            "tags": post_summary.tags,
            "authors": post_summary.authors,
            "markdown": markdown,
        }
    
        return {
            "status": {"code": 200, "text": "OK"},
            "headers": {"Content-Type": "application/json", "x-resolved-url": resolved_url},
            "body": {"kind": "text", "text": json.dumps(response_body)},
        }
  • Registers the 'fetch' tool with FastMCP using the @mcp.tool decorator, specifying the name 'fetch'.
    @mcp.tool(name="fetch")
  • Helper function to parse various input formats (post://slug, full URLs, bare slugs) into a post slug, used in the fetch handler.
    def _extract_slug_from_url(url: str) -> str | None:
        """Extract a post slug from user input.
    
        The MCP contract references HTTP-style requests, so we support a few shapes:
    
        - ``post://{slug}`` or ``ghost://{slug}`` custom schemes
        - Fully qualified Ghost URLs (``https://example.com/posts/{slug}``)
        - Bare slugs with no scheme
        """
    
        parsed = urlparse(url)
    
        if parsed.scheme in {"post", "ghost", ""}:
            if parsed.path and parsed.path.strip("/"):
                return parsed.path.strip("/")
            if parsed.netloc:
                return parsed.netloc
            return parsed.path or None
    
        if parsed.scheme in {"http", "https"}:
            path = parsed.path.strip("/")
            if not path:
                return None
            return path.split("/")[-1]
    
        return None
  • Helper function to construct or resolve the canonical HTTPS URL for a post, using post.url, fallback, or base + slug, used in fetch.
    def _canonical_post_url(post_summary: PostSummary, fallback_url: str | None = None) -> str | None:
        """Resolve a canonical, HTTP(S) URL for a post."""
    
        if post_summary.url:
            return post_summary.url
    
        if fallback_url:
            parsed_fallback = urlparse(fallback_url)
            if parsed_fallback.scheme in {"http", "https"} and parsed_fallback.netloc:
                return fallback_url
    
        base_url = settings.ghost_api_url
        if base_url and post_summary.slug:
            parsed_base = urlparse(base_url)
            if parsed_base.scheme and parsed_base.netloc:
                origin = f"{parsed_base.scheme}://{parsed_base.netloc}"
                return urljoin(origin.rstrip("/") + "/", post_summary.slug.strip("/"))
    
        return None

Tool Definition Quality

Score is being calculated. Check back soon.

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/philipithomas/mcp'

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