orca

orca

Enables standard MCP clients to inspect and query GTK application accessibility trees through ARIA-normalized, policy-filtered MCP tools.

Category
Visit Server

README

Orca — ATK Accessibility MCP Server

Captures the ATK (Accessibility Toolkit) widget tree from running GTK applications on Linux, normalizes it to ARIA roles/types, applies a configurable declarative security policy, and exposes the result as MCP tools to any standard MCP client (Claude, Cursor, Windsurf, etc.).

Quick Start

cd orca
just shell        # enter nix-shell with all dependencies
just server       # start the MCP server on stdio

Or manually:

nix-shell
PYTHONPATH=src python3 -m src

Architecture

orca/
├── shell.nix                 # nix-shell environment
├── pyproject.toml            # package config
├── Justfile                  # task runner
├── docs/
│   ├── README.md             # this file
│   ├── usage.md              # client integration guide
│   ├── policy.md             # policy engine reference
│   ├── atk.md                # ATK capture internals
│   └── contribute.md         # development guide
└── src/
    ├── __init__.py
    ├── __main__.py           # entry point
    ├── atk.py                # ATK tree capture
    ├── normalize.py          # ATK→ARIA normalization
    ├── policy.py             # declarative security policy
    ├── server.py             # MCP server
    └── default_policy.yaml   # ship-default policy

MCP Tools

Tool Params Description
get_tree none Full ARIA-normalized tree, policy-filtered
get_tree_for_app app_name: str Tree scoped to an app (fnmatch glob)
get_node_info node_id: str Single node lookup by obj_id
list_apps none Top-level app objects (name, pid, role)

Configuration

Policy

Policy files are loaded in this priority:

  1. ~/.config/atk-mcp/policy.yaml (user override)
  2. src/default_policy.yaml (bundled default)

If neither exists or either fails to parse, the server starts with default_action: allow and no user rules.

Policy is loaded once at startup — restart the server to pick up changes.

See docs/policy.md for the full schema and examples.

Nix Environment

All dependencies are managed via shell.nix. No uv, no virtualenv. Key packages:

  • python314 — runtime
  • python314Packages.pyatspi — ATK tree access
  • python314Packages.pygobject3 — GI introspection
  • python314Packages.mcp — MCP SDK v2
  • python314Packages.pydantic-settings — policy config
  • python314Packages.pyyaml — policy parsing
  • at-spi2-core, at-spi2-atk, atk, gtk3 — runtime libs

Usage

With Cursor

Add to ~/.cursor/mcp.json:

{
  "mcpServers": {
    "atk-accessibility": {
      "command": "nix-shell",
      "args": ["--run", "python -m src"],
      "cwd": "/path/to/orca"
    }
  }
}

With Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "atk-accessibility": {
      "command": "nix-shell",
      "args": ["--run", "python -m src"],
      "cwd": "/path/to/orca"
    }
  }
}

With Windsurf

Add to .mcp.json in your project:

{
  "mcpServers": {
    "atk-accessibility": {
      "command": "nix-shell",
      "args": ["--run", "python -m src"],
      "cwd": "/path/to/orca"
    }
  }
}

From the command line (interactive test)

just shell
python -m src    # runs indefinitely on stdio

Pipe a raw MCP request to test individual tools:

echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \
  | python -m src

Policy Engine

See docs/policy.md for the full reference.

Quick example — deny all heading nodes and redact textbox names:

default_action: allow
built_in_deny:
  aria_roles:
    - "password"
  state_keywords:
    - "hidden"
    - "invisible"
rules:
  - id: deny-headings
    conditions:
      role: "heading"
    action: deny
  - id: redact-forms
    conditions:
      role: "textbox"
    action: redact
    redact_fields:
      - "name"
      - "description"

ATK Capture

See docs/atk.md for internals. Key points:

  • Walks gi.repository.Atspi desktop root recursively
  • Fail-closed: subprocess isolation prevents GLib abort from crashing the server when no AT-SPI bus is available
  • Each node captures: obj_id, role (int), role_name, name, description, state_set, attributes, child_count, index_in_parent, app_name, pid

Normalization

See docs/normalize.md for the role map.

ATK integer roles (0–132) are mapped to ARIA role strings. Unmapped roles pass through as their role_name string. State names are translated (e.g. FOCUSEDfocused, CHECKEDchecked).

Development

See docs/contribute.md for the development guide.

just shell        # enter dev environment
just test         # run verification suite
just compile      # syntax check
just lint         # import + smoke check
just server       # start server for manual testing

Limitations

  • Wayland apps without AT-SPI: Some Wayland-native GTK apps don't expose AT-SPI interfaces. get_tree_for_app returns [] for those apps. Expected, not a bug.
  • No hot-reload: Policy is loaded once at startup.
  • Requires AT-SPI bus: Without a running accessibility bus (e.g. at-spi-bus-launcher), the ATK module returns [] gracefully.
  • Python 3.14+: No typing-extensions dependency.

License

MIT

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured