Skip to main content

Plugin-based FRC documentation agent as an MCP server for WPILib and vendor libraries

Project description

FIRST Agentic CSA

A plugin-based FRC documentation agent implemented as a Model Context Protocol (MCP) server. Search across WPILib and vendor documentation (REV, CTRE, Redux, PhotonVision) using natural language queries. Built for FIRST Robotics Competition teams and CSAs (Control System Advisors).

Features

  • Unified Search: Query WPILib + vendor docs with a single tool
  • Plugin Architecture: Extensible system for adding new documentation sources
  • BM25 Ranking: High-quality text search without embedding costs
  • Multi-Vendor Support: WPILib, REV Robotics, CTRE Phoenix, Redux Robotics, PhotonVision
  • Language Filtering: Filter results by Java, Python, or C++
  • Version Support: Search specific documentation versions (2024, 2025, etc.)

Installation

Quick Install (PyPI)

# Using uvx (recommended)
uvx first-agentic-csa

# Or with pip
pip install first-agentic-csa

From Source

If you want to modify or contribute to the project:

  1. Install uv (fast Python package manager):

    Windows (PowerShell):

    powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
    

    macOS/Linux:

    curl -LsSf https://astral.sh/uv/install.sh | sh
    
  2. Clone and install:

    git clone https://github.com/YOUR_USERNAME/first-agentic-csa.git
    cd first-agentic-csa
    uv sync
    

Quick Start

Running the Server

# With uv
uv run first-agentic-csa

# Or directly
python -m wpilib_mcp.server

Configure in Claude Desktop / Cursor

Add to your MCP configuration (claude_desktop_config.json or Cursor settings):

{
  "mcpServers": {
    "frc-docs": {
      "command": "uvx",
      "args": ["first-agentic-csa"]
    }
  }
}

If running from source:

{
  "mcpServers": {
    "frc-docs": {
      "command": "uv",
      "args": ["--directory", "/path/to/first-agentic-csa", "run", "first-agentic-csa"]
    }
  }
}

Configure in Other MCP Clients

The server uses stdio transport and is compatible with any MCP client.

Available Tools

search_frc_docs

Search FRC documentation across WPILib and vendor libraries.

query: "SparkMax configure"
vendors: ["all"] | ["wpilib", "rev", "ctre", "redux"]
version: "2025"
language: "Java" | "Python" | "C++"
max_results: 1-25

fetch_frc_doc_page

Fetch the full content of a documentation page by URL.

url: "https://docs.wpilib.org/en/stable/docs/software/commandbased/commands.html"

list_frc_doc_sections

List available documentation sections from vendors.

vendors: ["all"] | ["wpilib", "rev"]
version: "2025"
language: "Java"

Configuration

Edit config.json to customize plugin settings:

{
  "plugins": {
    "wpilib": {
      "enabled": true,
      "versions": ["2025"],
      "languages": ["Java", "Python", "C++"]
    },
    "rev": {
      "enabled": true,
      "languages": ["Java", "C++"]
    },
    "ctre": {
      "enabled": false
    }
  },
  "cache": {
    "ttl_seconds": 3600
  },
  "search": {
    "default_max_results": 10,
    "default_language": "Java"
  }
}

Supported Plugins

Plugin Vendor Documentation
wpilib WPILib docs.wpilib.org
rev REV Robotics docs.revrobotics.com
ctre CTRE Phoenix v6.docs.ctr-electronics.com
redux Redux Robotics docs.reduxrobotics.com
photonvision PhotonVision docs.photonvision.org

Building Documentation Indexes

Each plugin has its own index builder that vendors can maintain independently.

Using the convenience wrapper:

# Build all plugin indexes
python scripts/build_index.py all

# Build specific vendor
python scripts/build_index.py wpilib --version 2025
python scripts/build_index.py rev
python scripts/build_index.py ctre

Running plugin builders directly:

# Each plugin has its own build_index.py with vendor-specific options
python -m wpilib_mcp.plugins.wpilib.build_index --version stable --verbose
python -m wpilib_mcp.plugins.rev.build_index --verbose
python -m wpilib_mcp.plugins.ctre.build_index --version stable
python -m wpilib_mcp.plugins.redux.build_index

Plugin Development

Create a new plugin by following this structure:

plugins/
└── myplugin/
    ├── __init__.py
    ├── plugin.py        # Must export `Plugin` class
    ├── build_index.py   # Index builder script (vendor-maintained)
    └── data/
        └── index.json

Your Plugin class must implement PluginBase, and you should provide a build_index.py script:

Plugin Implementation

Your Plugin class must implement PluginBase:

from wpilib_mcp.plugins.base import PluginBase, PluginConfig, SearchResult, PageContent, DocSection

class Plugin(PluginBase):
    @property
    def name(self) -> str:
        return "myplugin"
    
    @property
    def display_name(self) -> str:
        return "My Plugin"
    
    @property
    def description(self) -> str:
        return "Description of my plugin"
    
    @property
    def supported_versions(self) -> list[str]:
        return ["2025"]
    
    @property
    def supported_languages(self) -> list[str]:
        return ["Java", "Python"]
    
    @property
    def base_urls(self) -> list[str]:
        return ["https://docs.example.com"]
    
    async def initialize(self, config: PluginConfig) -> None:
        # Load index, build search corpus
        pass
    
    async def search(self, query, version=None, language=None, max_results=10) -> list[SearchResult]:
        # Return search results
        pass
    
    async def fetch_page(self, url) -> PageContent:
        # Fetch and clean page content
        pass
    
    async def list_sections(self, version=None, language=None) -> list[DocSection]:
        # Return documentation sections
        pass

Index Builder

Create a build_index.py that extends BaseIndexBuilder:

from wpilib_mcp.utils.indexer import BaseIndexBuilder

class MyPluginIndexBuilder(BaseIndexBuilder):
    def __init__(self):
        super().__init__(
            vendor="myplugin",
            base_url="https://docs.example.com",
            max_pages=200,
        )
    
    @property
    def start_urls(self) -> list[str]:
        return ["https://docs.example.com/getting-started"]
    
    def should_crawl(self, url: str) -> bool:
        return "docs.example.com" in url
    
    def extract_section(self, soup, url) -> str:
        # Return section name based on URL/content
        return "General"
    
    def extract_language(self, soup, url) -> str:
        return "All"

if __name__ == "__main__":
    import asyncio
    asyncio.run(MyPluginIndexBuilder().build_and_save("latest", Path("data/index.json")))

Index File Format

Each plugin uses a JSON index with this structure:

{
  "vendor": "myplugin",
  "version": "2025",
  "built_at": "2025-01-15T00:00:00Z",
  "pages": [
    {
      "url": "https://docs.example.com/page",
      "title": "Page Title",
      "section": "Section Name",
      "language": "Java",
      "content": "Full searchable content...",
      "content_preview": "First 300 chars for display..."
    }
  ]
}

Development

Running Tests

uv run pytest tests/ -v

Project Structure

wpilib-mcp/
├── pyproject.toml          # Project configuration
├── config.json             # User configuration
├── src/wpilib_mcp/
│   ├── server.py           # MCP server entry point
│   ├── plugin_loader.py    # Plugin discovery/loading
│   ├── tool_router.py      # Routes tools to plugins
│   ├── utils/
│   │   ├── fetch.py        # HTTP with caching
│   │   ├── html.py         # HTML cleaning
│   │   └── search.py       # BM25 search
│   └── plugins/
│       ├── base.py         # Plugin base class
│       ├── wpilib/         # WPILib plugin
│       ├── rev/            # REV plugin
│       ├── ctre/           # CTRE plugin
│       └── redux/          # Redux plugin
├── scripts/
│   └── build_index.py      # Index builder script
└── tests/
    ├── test_search.py
    └── test_plugins.py

Example Queries

Finding Command-Based Programming docs:

search_frc_docs(query="command based programming subsystems", vendors=["wpilib"])

Comparing motor controllers:

search_frc_docs(query="SparkMax configuration", vendors=["rev"])
search_frc_docs(query="TalonFX configuration", vendors=["ctre"])

Looking up specific hardware:

search_frc_docs(query="CANcoder absolute position swerve", vendors=["ctre"])
search_frc_docs(query="through bore encoder", vendors=["rev"])

Cross-vendor search:

search_frc_docs(query="brushless motor closed loop velocity control", vendors=["all"])

MCP Registry & VS Code Marketplace

This MCP server is available in the official MCP Registry and can be discovered through VS Code's MCP integration.

Finding in VS Code

  1. Open VS Code Extensions view
  2. Search for "MCP" or "WPILib"
  3. Browse available MCP servers
  4. Install and configure through VS Code's MCP settings

Registry Listing

For publishing and registry management, see PUBLISHING.md.

License

BSD-3-Clause License - see LICENSE file for details.

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Add tests for new functionality
  3. Submit a pull request

For new vendor plugins, please include:

  • Complete plugin implementation
  • Pre-built index file
  • Documentation updates

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

first_agentic_csa-0.3.6.tar.gz (743.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

first_agentic_csa-0.3.6-py3-none-any.whl (692.3 kB view details)

Uploaded Python 3

File details

Details for the file first_agentic_csa-0.3.6.tar.gz.

File metadata

  • Download URL: first_agentic_csa-0.3.6.tar.gz
  • Upload date:
  • Size: 743.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for first_agentic_csa-0.3.6.tar.gz
Algorithm Hash digest
SHA256 12a12188202aad16548dab5021d30f5777992972ecd718dc00b79380eeb838c9
MD5 5ed9eb4ba95efa240adcffea456db19d
BLAKE2b-256 f70b207cf042c6bfd60ae1ad2b01b0de43f1a900a621a4627f310ea1bce12229

See more details on using hashes here.

File details

Details for the file first_agentic_csa-0.3.6-py3-none-any.whl.

File metadata

  • Download URL: first_agentic_csa-0.3.6-py3-none-any.whl
  • Upload date:
  • Size: 692.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.9.16 {"installer":{"name":"uv","version":"0.9.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for first_agentic_csa-0.3.6-py3-none-any.whl
Algorithm Hash digest
SHA256 5b83dd69e6d70b47c2b97c9d2ed97c30d98e593eb62e642ccb7936b7f351a00e
MD5 9321317af96da260c2eaee345dc8d0a6
BLAKE2b-256 ff249037efdc25366883a7445848a2ef11af627a14fac6e36c47b24f3324a6b5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page