Skip to main content
Glama
iFixit MCP Server

iFixit MCP Server

by Dthen

iFixit MCP Server

Full-coverage iFixit MCP server — repair guides, device info, repairability scores, categories, search, media, and contributor profiles in one server.

⚠️ LICENSE — READ FIRST

Two licenses apply — do not confuse them:

  1. The code in this repository is licensed under the 0-Clause BSD License (0BSD) — free to use, copy, modify, and distribute for any purpose, including commercial use.

  2. The data the server surfaces comes from the iFixit API and remains iFixit content under a non-commercial CC BY-NC-SA license. Commercial use of iFixit data requires contacting api@ifixit.com for pricing, and per iFixit's Terms of Service: "Training Large Language Models on iFixit content is prohibited."

This server is a read-only, on-demand lookup tool — like a search engine returning snippets, not bulk ingestion for training. It deliberately:

  • Never bulk-downloads or persistently caches the guide corpus. Every request fetches on demand; the in-memory cache is bounded (256 entries) and mirrors iFixit's own CDN TTL (30 min).

  • Has no LLM-training features — no dataset export, no bulk endpoints, no scraping modes.

  • Identifies iFixit in every tool description; the CC BY-NC-SA terms are documented in this README and the LICENSE section.

Your 0BSD rights cover the code only, not iFixit's content: keep your use of iFixit data non-commercial, and contact iFixit first if your use case is commercial or involves training.

Why this server?

Research found no existing iFixit MCP servers; this is the first server to cover the full public read surface of the iFixit API 2.0:

  • Search across guides, wikis, questions, products (/suggest)

  • Repair guides — summary or full detail, with steps, parts, and tools

  • Device wiki pages — repairability scores (when iFixit has published one), featured guides, parts/tools counts

  • Category tree — ~16 top-level categories down to nested sub-devices

  • Maintenance schedules — battery/SSD health triggers and other upkeep tasks

  • Media CDN URLs — images, videos, documents by id

  • Contributor profiles — reputation, badges, and guide lists

  • 8 tools, all anonymous and read-only — zero configuration, no API keys, no tokens

Related MCP server: osrs-wiki-mcp

Quick start

cd <repo-root>            # e.g. git clone <repo-url> && cd ifixit-mcp
# Any Python 3.10+ venv works; the server is dependency-free (Python stdlib only)
# — no fastmcp, no httpx, no external packages needed at runtime
python3 -m venv .venv
.venv/bin/pip install -e .

Run the server (stdio):

.venv/bin/python -m ifixit_mcp.server

Configuration

Hermes Agent

Add to your Hermes config.yaml:

mcp_servers:
  ifixit:
    command: /absolute/path/to/ifixit-mcp/.venv/bin/python3
    args: ['-m', 'ifixit_mcp.server']

Claude Desktop

Add to claude_desktop_config.json — no npx, no Node.js: this is a pure-Python stdio server:

{
  "mcpServers": {
    "ifixit": {
      "command": "/absolute/path/to/ifixit-mcp/.venv/bin/python3",
      "args": ["-m", "ifixit_mcp.server"]
    }
  }
}

Any Python 3.10+ interpreter works in place of the Hermes venv path, as long as the package is installed (or PYTHONPATH points at src/). No environment variables, API keys, or tokens are required for any tool.

Tool reference

All tools are read-only and anonymous. Tool failures are delivered to the MCP client as error results with isError: true — never returned as success strings and never as stack traces. The content text is always compact JSON of the form {"error":"<message>"}. Handler-generated messages may include a family prefix, such as {"error":"Guide lookup failed: Guide not found: 1220"}; dispatch and validation errors may be bare, such as {"error":"Unknown tool: not_a_tool"}.

Tool

Params

Returns

search_guides

query, device?, doctypes="guide", lang?

{query, results} — up to 10 search results; guide results compacted to {guideid, title, url, type, difficulty, summary} with summary truncated to 200 chars; other types (wiki, question, product) passed through. lang (e.g. "de") requests localized results. Never cached.

get_guide

guideid, detail="summary", max_steps?, lang?

Guide metadata, parts/tools lists, and step titles only (summary, default) or the full guide (full). In both modes *_rendered HTML is converted to plain text and renamed *_text (step lines: text); summary steps with empty titles fall back to the first line's text (teardown guides often have blank titles); max_steps truncates the steps list in full mode. lang (e.g. "de") requests a localized guide. Cached 30 min.

browse_categories

path?

~16 top-level category names (no path), or the child category names of a subtree (e.g. "Mac/Mac Laptop"); an empty path means top level. Only names are returned — the raw ~1.5 MB tree never leaves the client. Cached 30 min.

get_device

title

Compact device overview: title, display_title, repairability_score (included only when iFixit has published one — it is null/absent for many devices), summary (first 500 chars), featured_guides (title/guideid/url), children (names only), parts_count (list length or, for the live object shape {url, categories:[{tag,count}]}, the sum of the category counts), tools_count, ancestors (breadcrumb names only). Cached 30 min.

list_device_guides

title

The device's guides and featured guides (deduplicated) as a compact list — each entry {guideid, title, url, difficulty, time_required_max, image_thumbnail}, optional fields omitted when absent. Cached 30 min.

get_maintenance_schedule

title

{schedules: [...]} — maintenance tasks and their triggers (e.g. battery_health_percent); {schedules: []} (HTTP 200) when the device has none; inherited_from (parent device name) when the schedule is inherited. Cached 30 min.

get_media

media_id, media_type="images"

The media object with CDN size URLs (mini, thumbnail, standard, original, ...); ungenerated sizes are absent. media_type ∈ images/videos/documents. Cached 1 hour.

get_user

user_id, include_guides=False, limit=20

Contributor profile (username, reputation, join_date, badge_counts, ...); with include_guides=True, merges the user's guides projected to {guideid, title, url} (up to limit guides, 1-200). Cached 30 min.

Response-size management

iFixit's raw API responses are far too large for LLM context budgets, so every tool compacts what it returns:

Raw API payload

Size

What the server returns

Full guide (/guides/{id})

~25 KB small guides, 100 KB+ for large ones (prerequisite steps inlined, full HTML, comments, flags)

summary mode: metadata + parts/tools + step titles only (empty titles fall back to the first line's text); full mode: *_raw markup stripped, *_rendered HTML converted to plain text and renamed *_text (step lines: text), max_steps truncation

Category tree (/categories)

~1.5 MB nested object

Projected name lists only — top-level names or one subtree's children; the tree itself never leaves the client

Device wiki page (/wikis/CATEGORY/{title})

~238 KB, 39 keys

9-field projection: repairability score, 500-char summary, featured-guide stubs, child names, parts/tools counts, ancestors

Search results (/suggest/{q})

Mixed guide/wiki/question objects

Guide results projected to 6 fields with summary truncated to 200 chars at the tool layer; other types already small, passed through

Beyond projection, the client keeps memory bounded:

  • Bounded TTL cache — 256-entry in-memory cache, oldest entries evicted first. TTLs mirror iFixit's CDN edge TTL (observed x-debug-ttl: 1800): 30 min for guides/devices/categories/schedules/users, 1 hour for media. Entries are deep-copied on read and write so callers can never corrupt cached data (category-tree navigation reads the cached tree without copying — it is strictly read-only).

  • Volatile endpoints never cached — search (/suggest) and paginated lists (/guides, /users/{id}/guides) bypass the cache entirely.

  • No bulk access — there is no tool that enumerates the corpus; every tool is a targeted, on-demand lookup.

Development

Test-driven workflow: client behavior → server tool wiring → end-to-end tool tests.

# Install
pip install -e .

# Run the full suite (558 tests)
pytest tests/ -v

Project layout:

ifixit-mcp/
├── src/ifixit_mcp/
│   ├── __init__.py
│   ├── client.py      # IfixitClient — sync urllib client, all API logic
│   └── server.py      # era-only JSON-RPC server (thin handlers + projections)
├── tests/
│   ├── conftest.py
│   ├── test_client.py
│   ├── test_server.py
│   └── test_tools.py
├── CHANGELOG.md       # release history (Keep a Changelog)
├── openapi.json       # Official iFixit API 2.0 OpenAPI 3.1 spec (1.16 MB)
└── pyproject.toml

Architecture

LLM / MCP client
      │  (JSON-RPC over stdio)
      ▼
server.py  ── era-only JSON-RPC 2.0 server (stdio loop)
      │        • input validation at dispatch
      │        • every tool failure → isError result whose compact content
      │          text is {"error":"<message>"}; some messages have a family
      │          prefix, while dispatch/validation errors may be bare
      ▼
client.py  ── IfixitClient (sync urllib → https://www.ifixit.com/api/2.0)
              • descriptive User-Agent on every request (no fabricated URL)
              • bounded in-memory TTL cache (256 entries, deep-copied)
              • simple rate limiter (minimum interval between requests)
              • 429 retry with exponential backoff (honors Retry-After,
                capped at 8s, ≤3 retries)
              • error mapping: 400/401 → ValueError, 403 → ForbiddenError,
                404 → NotFoundError (both ValueError subclasses)
              • response compaction: _summarize_guide, _full_guide,
                _project_device, _compact_guide_item, _html_to_text
  • server.py — the stdlib-only era server. Reads newline-delimited JSON-RPC 2.0 requests from stdin, dispatches to handlers via validate_args (hand-written, no pydantic), and writes results to stdout. The one supported entry point is server/discover (returning supportedVersions: ["2026-07-28"]); the legacy initialize method returns JSON-RPC error -32601 by design (D2). server/discover, tools/list, and tools/call results carry the era-strict resultType/ttlMs/cacheScope triple; the protocol ping empty result intentionally does not. Tools never declare outputSchema. Tool-level failures return isError results; protocol faults use JSON-RPC error codes. No launcher, no SIGTERM/atexit handling, no framework — just Python stdlib.

Protocol

This server speaks the 2026-07-28 stateless era of the MCP protocol — no framework, no external dependencies, just Python stdlib over newline-delimited JSON-RPC 2.0 on stdio.

  • Era-only support. server/discover returns supportedVersions: ["2026-07-28"]. The legacy initialize method returns JSON-RPC error -32601 by design (D2) — the era model is stateless; there is no session, no capability negotiation, no instructions.

  • Era results carry the era-strict triple: server/discover, tools/list, and tools/call include resultType ("complete"), ttlMs (0), and cacheScope ("private") via era_result(). The protocol ping method intentionally returns an empty result without that triple.

  • Tools never declare outputSchema — the D3 trap (where declaring it forces structuredContent emission and breaks stateless clients) is avoided at the source. The tool listing is the literal TOOLS constant.

  • Tool failures return isError results ({"content": [...], "isError": true}) whose compact content text is always {"error":"<message>"} — never as JSON-RPC error codes, never as stack traces. Handler messages may include a family prefix; dispatch/validation messages may be bare.

  • Protocol faults use JSON-RPC error codes — malformed requests, unknown methods, and dispatch-level exceptions return proper {"error": {"code": ..., "message": ...}} objects.

  • No launcher, no signals, no atexit. The server is started with python -m ifixit_mcp.server. It exits only on stdin EOF; SIGTERM is not trapped; the OS reclaims sockets on process exit.

  • Hermes auto and stateless both connect. The standard config (command: <venv-python>, args: ['-m', 'ifixit_mcp.server']) works for both the auto-detect and stateless transport modes.

Known limitations

  • Every tool parameter is string-typed with explicit coercion: JSON numbers are coerced to strings and then validated (get_guide with guideid: 1220 works; search_guides with query: 0 searches for "0"); JSON booleans and junk types are rejected, and nulls are rejected for required params (omitted for optional ones) — all with clean family messages, never silent true → 1 fetches, searches for the literal "None", or raw pydantic dumps. A missing required parameter (e.g. calling search_guides with no arguments at all) now also yields a clean message — validation is hand-written at dispatch (validate_args/handle_call, T09), so no validation library runs in the process and no raw dump can ever surface. Everything the client or dispatch path can see is converted to a clean message.

License

This project has a dual license structure — the code and the data it serves are licensed separately:

  • Code — the software in this repository is licensed under the 0-Clause BSD License (0BSD): free to use, copy, modify, and distribute for any purpose, with or without fee (SPDX: 0BSD). https://opensource.org/license/0bsd · the full text is in LICENSE.

  • Data — the iFixit content surfaced through this server (guides, wiki pages, media, and other API responses) remains iFixit's content under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) license: non-commercial use only, attribution required, and LLM training on iFixit content is prohibited per iFixit's Terms of Service. https://creativecommons.org/licenses/by-nc-sa/4.0/

The 0BSD grant covers the code only. This server is a read-only, on-demand lookup tool — it never bulk-caches the guide corpus, and nothing in the code license authorizes bulk-ingesting or training on iFixit content.

  • openapi.json — official iFixit API 2.0 OpenAPI 3.1 spec (56 paths, 53 schemas)

  • iFixit API docs — official API documentation and licensing terms

Available Tools

8 tools
browse_categoriesA

Browse iFixit's device category tree.

With no path, returns the ~16 top-level category names (e.g. Mac, Phone, Game Console). With a path ("Mac" or "Mac/Mac Laptop"), navigates the nested tree and returns that subtree's child category names. A leaf or empty subtree yields an empty list. Only category names are returned — the raw tree is ~1.5MB and never leaves the client.

Args: path: Optional slash-separated category path to descend into (e.g. "Mac" or "Mac/Mac Laptop"); an empty string means the top level.

Note: Data from iFixit (CC BY-NC-SA). Non-commercial use only.

Inputs: path. Returns: result

get_deviceA

Get a compact overview of a device wiki page.

Returns {title, display_title, repairability_score (when iFixit has published one), summary (first 500 chars), featured_guides (title/guideid/url only), children (names only), parts_count, tools_count, ancestors (breadcrumb names)}. The raw wiki page can be ~238KB; this projection keeps the response small for context budgets.

Args: title: The device title (e.g. "iPhone").

Note: Data from iFixit (CC BY-NC-SA). Non-commercial use only.

Inputs: title (required). Returns: result

get_guideA

Fetch a repair guide by id.

With detail="summary" (default) returns the guide's metadata, parts and tools lists, and step titles only — a compact overview (steps with empty titles fall back to the first line's text). With detail="full" returns everything (steps with rendered text converted to plain text). max_steps truncates the steps list; note it only applies when detail="full" — in summary mode the client ignores it, so the combination is accepted but has no effect.

WARNING: detail="full" guides can exceed 250KB of text — prefer detail="summary" or set max_steps for large guides.

Args: guideid: The guide id (e.g. 1220 or "1220"). detail: One of "summary" (default) or "full". max_steps: Maximum number of steps to include when detail="full" (e.g. 10 or "10"). lang: Optional language code (e.g. "de") for a localized guide (maps to the API's langid parameter).

Note: Data from iFixit (CC BY-NC-SA). Non-commercial use only.

Inputs: guideid (required), lang, detail, max_steps. Returns: result

get_maintenance_scheduleA

Get a device's maintenance schedule.

Returns {"schedules": [...]} where each schedule describes a maintenance task and its trigger (e.g. battery_health_percent). When the device inherits its schedule from a parent device, the dict also carries "inherited_from" (the parent's name). A device with no maintenance schedule yields {"schedules": []} — that is the API's normal "no schedule" signal (HTTP 200), not an error.

Args: title: The device title (e.g. "iPhone").

Note: Data from iFixit (CC BY-NC-SA). Non-commercial use only.

Inputs: title (required). Returns: result

get_mediaA

Resolve a media object's CDN URLs by id.

Returns the API's image/media object with CDN size URLs (mini, thumbnail, standard, original, ...); ungenerated sizes are absent. Media access is permission-checked: assets not referenced by content you can view return an error.

Args: media_id: The media id (e.g. 14056 or "14056"). media_type: One of "images" (default), "videos", or "documents".

Note: Data from iFixit (CC BY-NC-SA). Non-commercial use only.

Inputs: media_id (required), media_type. Returns: result

get_userA

Fetch an iFixit contributor profile.

Returns the user's profile dict (username, reputation, join_date, badge_counts, ...). With include_guides=True, merges the profile with the user's guide list into {"user": ..., "guides": [...]} where each guide is projected to {guideid, title, url}.

include_guides is all-or-nothing: if either the profile fetch or the guide-list fetch fails (ValueError, network error, or malformed response), the whole call raises a single clean error — partial data is never returned.

Args: user_id: The user id (e.g. 1 or "1"). include_guides: When True, also fetch and include the user's guides (projected to guideid/title/url). Accepts true/false (also as JSON booleans) or 1/0; any other value is rejected with a clean error. limit: Maximum number of guides to include when include_guides=True (1-200, default 20; e.g. 5 or "5"). The API clamps at 200. Validated unconditionally — junk is rejected even when include_guides=False leaves it unused (QA Round 12, F12-7).

Note: Data from iFixit (CC BY-NC-SA). Non-commercial use only.

Inputs: user_id (required), limit, include_guides. Returns: result

list_device_guidesA

List the repair guides available for a device.

Returns the device's guides (and featured guides) as a compact list — each entry is projected to {guideid, title, url, difficulty, time_required_max, image_thumbnail}, with optional fields omitted when the API did not provide them.

Args: title: The device title (e.g. "iPhone").

Note: Data from iFixit (CC BY-NC-SA). Non-commercial use only.

Inputs: title (required). Returns: result

search_guidesA

Search iFixit's catalog for repair guides (and other content types).

Returns up to 10 results as {"query": ..., "results": [...]}. Guide results are compacted to {guideid, title, url, type, difficulty, summary} with summary truncated to 200 characters; other result types (wiki, question, product) pass through as returned by the API. Use the device parameter to scope results to a specific device (e.g. "iPhone 13"). Search results are volatile and never cached.

Args: query: Free-text search query (e.g. "battery replacement"). device: Restrict results to a single device by name (maps to the API's guideDevice parameter). doctypes: Comma-separated result types: guide, item, topic, device, category, question, post, or all (default "guide"). lang: Optional language code (e.g. "de") for localized results (maps to the API's langid parameter).

Note: Data from iFixit (CC BY-NC-SA). Non-commercial use only.

Inputs: query (required), lang, device, doctypes. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.6/5.0

    Scored across 8 tools

    Disambiguation5/5

    Each tool targets a distinct resource or action: guides, maintenance schedules, media, users, search, categories, and devices. There is no meaningful overlap—list_device_guides and get_guide differ by granularity, and browse_categories complements get_device rather than duplicating it.

    Naming Consistency5/5

    All tool names follow a consistent verb_noun pattern in snake_case: get_ for fetching specific entities, list_/search_/browse_ for discovery. This is uniform and predictable.

    Tool Count5/5

    Eight tools is well within the ideal 3–15 range and covers the read-only iFixit domain without bloat. Each tool earns its place, and the count is appropriate for the server's stated purpose.

    Completeness5/5

    The surface covers the core workflows: discovering devices, browsing categories, listing and fetching guides, searching, retrieving maintenance schedules, user profiles, and media assets. As a read-only server, there are no obvious lifecycle gaps—the only missing operations (create/update/delete) are not part of the domain.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Read-only MCP tools for authenticated Open Science Framework projects, components, files, and contributors.
      6
      1
      Apache 2.0
    • A
      license
      A
      quality
      B
      maintenance
      Provides read-only access to Old School RuneScape Wiki data, returning structured content with source provenance via MCP tools for searching pages, items, monsters, quests, shops, and drop sources.
      10
      234 npm
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Provides read-only access to Mediawork's public directory of post-production and distribution vendors, FAQ, blog, and subscription plans through standardized MCP tools for searching and fetching records.
      MIT