Reasonix Plugin System Architecture and MCP Server Integration: A Deep Dive

The Reasonix plugin system treats external MCP (Model-Capability-Protocol) servers as first-class citizens by spawning them as separate processes, discovering their tools through a stdio-based handshake, and registering them in a global registry that exposes portable aliases to the skill system and UI model picker.

The DeepSeek-Reasonix repository implements a sophisticated plugin architecture that bridges external AI capabilities with its core reasoning engine. This system leverages the Model-Capability-Protocol (MCP) to standardize how external tools and models are discovered, registered, and invoked. Understanding the Reasonix plugin system architecture reveals how the platform maintains strict separation between core logic and extensible capabilities while providing seamless MCP server integration.

Configuration Layer: Declaring MCP Plugins

TOML Schema and Validation

Plugin declarations reside in the user-editable TOML configuration under the [[plugins]] array. Each entry requires three mandatory fields: name (unique identifier), type (currently restricted to "mcp"), and command (the executable launch string). An optional tier field controls initialization timing, with "eager" forcing immediate startup.

Validation logic in internal/repair/diagnose.go (lines 172-186) enforces schema constraints before the host attempts process creation. This validator ensures plugin names are unique across the configuration and that the command string is non-empty, preventing runtime failures during the spawn phase.


# Example: Declaring a Figma MCP plugin in config.toml

[[plugins]]
name = "figma"
type = "mcp"
command = "figma-mcp-server --port 0"
tier = "eager"

Process Management and the MCP Handshake

Spawning External Processes

When Reasonix initializes, the host process—whether launched via cmd/reasonix/main.go into desktop mode or serve mode—spawns each configured plugin as a separate operating system process. The host establishes a bidirectional stdio channel using exec.Command, binding the plugin's standard input and output to the parent process for JSON-RPC communication.

Tool Discovery and Metadata Interfaces

After process spawn, the MCP handshake protocol begins. The external server advertises its available tools by implementing metadata interfaces defined in internal/tool/tool.go (lines 119-125). Each tool must satisfy one or more of these contracts:

  • MCPMetadata: Base interface providing server and tool identifiers
  • MCPVisibleMetadata: Exposes human-readable tool names for UI rendering
  • MCPPackageMetadata: Associates tools with specific plugin packages for namespacing

Once discovered, every tool registers in the global tool.Registry, mixing built-in capabilities with plugin-provided MCP tools under a unified access layer.

Tool Registry and Portable Naming Conventions

Canonical Alias Generation

The registry constructs portable, deterministic identifiers to ensure stable references across sessions. For each MCP tool, Reasonix generates canonical aliases following the pattern mcp__<server>__<tool>, where both components undergo normalization to handle special characters safely. This logic resides in internal/tool/tool.go (lines 306-478).

The system creates aliases for both the raw tool name and the visible display name, ensuring that skills can reference capabilities using either technical identifiers or human-readable labels.

Plugin-Specific Namespacing

To prevent collisions between built-in tools and plugin-provided capabilities, Reasonix constructs plugin-specific aliases that incorporate the package name: mcp__plugin_<pkg>_<server>__<tool>. This prefixing strategy allows multiple plugins to expose tools with identical base names without namespace pollution, while the portable aliases provide a stable interface for skill authors.

// Simplified alias generation from internal/tool/tool.go
func mcpBindingAliases(b tool.MCPBinding) []string {
    aliases := []string{
        "mcp__" + portableMCPPart(b.Server) + "__" + portableMCPPart(b.RawName),
        "mcp__" + portableMCPPart(b.Server) + "__" + portableMCPPart(b.VisibleName),
    }
    // Plugin-specific variant adds package namespace
    prefix := "mcp__plugin_" + portableMCPPart(b.Package) + "_" + portableMCPPart(b.Server) + "__"
    aliases = append(aliases,
        prefix+portableMCPPart(b.RawName),
        prefix+portableMCPPart(b.VisibleName))
    return aliases
}

Skill Integration and Capability Binding

Runtime Binding Injection

When a skill loads from a plugin package, the system invokes Store.ConfigureToolBindings defined in internal/skill/skill.go (lines 242-251). This resolver injects MCP bindings directly into the skill's markdown context, appending a "Runtime MCP tool bindings" section that enumerates available capabilities and their stable use_capability identifiers.

The binding process maps portable MCP names to concrete, host-generated aliases, ensuring that skills reference tools through deterministic IDs regardless of the underlying server implementation. Before execution, the dispatcher verifies authorization through MCPServerAuthorization and HasNonDestructiveMCPExecutionIntent checks to enforce safety boundaries.


## Runtime MCP tool bindings

These host-generated bindings are authoritative for this invocation.
Use the exact direct name below; if only `use_capability` is available, 
use the stable capability ID.

use_capability mcp__figma__search

UI Exposure and Model Selection

Provider Catalog Integration

The plugin architecture extends to the UI layer through model reference paths formatted as plugin/<plugin>/<provider>/<model>. The HTTP and desktop front-ends enumerate available models by querying the ProviderCatalog, which aggregates entries from both built-in providers and active MCP servers.

This integration logic in internal/serve/serve.go (lines 1000-1030) parses plugin-prefixed model identifiers, resolving them to the appropriate MCP process capabilities. Users can select plugin-exposed models directly from the model picker alongside native Reasonix providers, creating a seamless experience where external AI services appear as first-class options.

Summary

  • Three-layer architecture: Configuration validation, process management, and registry binding work sequentially to initialize and expose MCP capabilities
  • Portable naming: The mcp__<server>__<tool> pattern provides stable references, while plugin-specific prefixes prevent namespace collisions
  • Automatic skill enrichment: The ConfigureToolBindings mechanism injects capability mappings into skill markdown without manual configuration
  • Unified UI integration: The ProviderCatalog treats MCP-exposed models identically to built-in providers, supporting the plugin/<plugin>/<provider>/<model> reference format

Frequently Asked Questions

How does Reasonix validate plugin configurations before startup?

Validation occurs in internal/repair/diagnose.go (lines 172-186), where the system checks that each plugin has a unique name, a valid type (currently limited to "mcp"), and a non-empty command string. This prevents runtime spawn failures and namespace collisions during the initialization phase.

What is the difference between portable MCP names and plugin-specific aliases?

Portable names follow the pattern mcp__<server>__<tool> and provide a stable interface for skill authors, while plugin-specific aliases incorporate the package identifier as mcp__plugin_<pkg>_<server>__<tool>. The portable variant ensures consistency across different installations, whereas the plugin-specific variant prevents naming collisions when multiple plugins expose similar tools.

How does the skill system resolve tool calls to MCP server processes?

When a skill invokes use_capability, the dispatcher consults the runtime bindings injected by Store.ConfigureToolBindings in internal/skill/skill.go. This resolver maps the capability ID to the specific MCP server process, verifies authorization via MCPServerAuthorization, and forwards the JSON-RPC call through the stdio channel established during process spawn.

Can Reasonix integrate with non-MCP external tools?

Currently, the plugin system exclusively supports the MCP protocol as indicated by the type = "mcp" constraint in configuration validation. The architecture assumes stdio-based JSON-RPC communication and the specific metadata interfaces defined in internal/tool/tool.go, making MCP the sole supported integration pattern for external capabilities.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →