# How to Contribute to the Unity MCP Project: A Complete Developer Guide

> Learn how to contribute to the Unity MCP project. Fork the CoplayDev/unity-mcp repo, code, test, and submit a pull request to join development.

- Repository: [Coplay/unity-mcp](https://github.com/CoplayDev/unity-mcp)
- Tags: how-to-guide
- Published: 2026-07-07

---

**To contribute to the Unity MCP project, fork the CoplayDev/unity-mcp repository, create a feature branch off `beta`, implement parallel changes in both the Python MCP layer (`Server/src/services/tools/`) and the Unity C# layer (`MCPForUnity/Editor/Tools/`), add comprehensive tests for both codebases, and submit a pull request targeting the `beta` branch.**

The Unity MCP (Model Context Protocol) bridge enables AI assistants to control the Unity Editor through a dual-layer architecture. Contributors to the CoplayDev/unity-mcp repository must maintain **domain symmetry** by implementing every feature in both Python (the MCP server side) and C# (the Unity Editor side). This guide walks you through the complete contribution workflow based on the project's [`CONTRIBUTING.md`](https://github.com/CoplayDev/unity-mcp/blob/main/CONTRIBUTING.md) and [`CLAUDE.md`](https://github.com/CoplayDev/unity-mcp/blob/main/CLAUDE.md) specifications.

## Understanding the Unity MCP Architecture

The repository contains two parallel codebases that communicate via the MCP protocol. Before contributing, understand where your changes must reside:

- **Python MCP Tools** (`Server/src/services/tools/`) – Exposed to AI assistants via the `@mcp_for_unity_tool` decorator. These handle protocol-level communication and forward commands to Unity.
- **CLI Commands** (`Server/src/cli/commands/`) – Python Click interfaces for terminal-based development workflows.
- **Resources** (`Server/src/services/resources/`) – Read-only state exposed via `@mcp_for_unity_resource` decorators.
- **Unity Editor Tools** (`MCPForUnity/Editor/Tools/`) – C# implementations using the `[McpForUnityTool]` attribute that actually execute operations within the Unity Editor.

- **Compatibility Shims** (`MCPForUnity/Runtime/Helpers/`) – Version-specific adapters for Unity API changes.

Any functional change requires updates to both the Python tool definition and its corresponding C# handler to maintain protocol compatibility.

## Setting Up Your Development Environment

Start by forking the repository and configuring your local workspace to track the upstream `beta` branch.

1. Fork the repository on GitHub, then clone your fork:

```bash
git clone https://github.com/<your-username>/unity-mcp.git
cd unity-mcp

```

2. Add the upstream remote and create your feature branch:

```bash
git remote add upstream https://github.com/CoplayDev/unity-mcp.git
git fetch upstream
git checkout -b feat/your-feature-name upstream/beta

```

The project uses the `beta` branch as the active development target. Never open pull requests against `main` unless specifically requested by maintainers.

## Implementing a New Tool (Parallel Implementation)

When adding functionality, you must create mirrored implementations in both languages. The following example demonstrates registering a new tool called `manage_example`.

### Python MCP Tool Implementation

Create your tool definition in [`Server/src/services/tools/manage_example.py`](https://github.com/CoplayDev/unity-mcp/blob/main/Server/src/services/tools/manage_example.py). The `@mcp_for_unity_tool` decorator registers the function with the MCP server:

```python

# Server/src/services/tools/manage_example.py

from services.registry import mcp_for_unity_tool

@mcp_for_unity_tool(
    description="Demonstrates a simple example tool.",
    group="core",
)
async def manage_example(ctx, action: str) -> dict:
    unity = await get_unity_instance_from_context(ctx)
    params = {"action": action}
    return await send_with_unity_instance(
        async_send_command_with_retry, unity, "manage_example", params
    )

```

Key components include:
- **`@mcp_for_unity_tool`** – Registers the function with metadata for AI assistants.
- **`get_unity_instance_from_context`** – Retrieves the active Unity connection from the request context.
- **`send_with_unity_instance`** – Forwards the command to the Unity Editor process with automatic retry logic.

### C# Unity Editor Implementation

Create the counterpart in [`MCPForUnity/Editor/Tools/ManageExample.cs`](https://github.com/CoplayDev/unity-mcp/blob/main/MCPForUnity/Editor/Tools/ManageExample.cs). The `[McpForUnityTool]` attribute maps this class to the Python tool:

```csharp
// MCPForUnity/Editor/Tools/ManageExample.cs
using UnityEngine;
using UnityEditor;
using McpForUnity;

[McpForUnityTool("manage_example", AutoRegister = true, Group = "core")]
public static class ManageExample
{
    public static object HandleCommand(JObject @params)
    {
        var p = new ToolParams(@params);
        string action = p.RequireString("action");
        Debug.Log($"Example tool received action: {action}");
        return new SuccessResponse("Done.", new { echo = action });
    }
}

```

Critical elements:
- **`[McpForUnityTool]`** – Maps the C# handler to the Python tool name (must match exactly).

- **`HandleCommand`** – The entry point that receives JSON parameters from the Python side.
- **`ToolParams`** – Helper class for type-safe parameter extraction.
- **`SuccessResponse`** – Standardized response format for the MCP protocol.

## Testing Your Changes

Every contribution requires tests for both the Python and C# implementations.

### Python Tests

Add asynchronous pytest cases in `Server/tests/`:

```python

# Server/tests/test_manage_example.py

import pytest
from services.tools.manage_example import manage_example

@pytest.mark.asyncio
async def test_example_action():
    ctx = make_test_context()
    resp = await manage_example(ctx, action="demo")
    assert resp["status"] == "success"
    assert resp["data"]["echo"] == "demo"

```

### Unity Edit-Mode Tests

Add NUnit tests in the Unity test project:

```csharp
// TestProjects/UnityMCPTests/Assets/Tests/ManageExampleTests.cs
using NUnit.Framework;
using UnityEngine;
using UnityEditor;
using McpForUnity.Editor.Tools;

public class ManageExampleTests
{
    [Test]
    public void HandlesCommand()
    {
        var result = ManageExample.HandleCommand(
            JObject.FromObject(new { action = "ping" })
        );
        Assert.IsTrue(result is SuccessResponse);
    }
}

```

## Local Verification and Submission

Before pushing, verify your changes pass the full validation suite.

Run Python tests using `uv`:

```bash
cd Server
uv run pytest tests/ -v

```

Verify Unity compilation across supported versions:

```bash
tools/check-unity-versions.sh

```

This script ensures your C# changes compile against all supported Unity Editor versions.

When ready to submit:
1. Push your branch: `git push origin feat/your-feature-name`
2. Open a pull request on GitHub targeting the `beta` branch
3. Complete the PR template checklist (verify branch origin, test coverage, documentation updates, and removal of dead code)

## Summary

- **Fork and branch** off `beta` (not `main`) when starting work on CoplayDev/unity-mcp.
- **Maintain domain symmetry** by implementing every tool in both `Server/src/services/tools/` (Python) and `MCPForUnity/Editor/Tools/` (C#).
- **Use the correct decorators and attributes**: `@mcp_for_unity_tool` for Python and `[McpForUnityTool]` for C#.
- **Test both layers**: Python tests in `Server/tests/` and Unity Edit-mode tests in `TestProjects/UnityMCPTests/Assets/Tests/`.
- **Validate locally** using `uv run pytest` and [`tools/check-unity-versions.sh`](https://github.com/CoplayDev/unity-mcp/blob/main/tools/check-unity-versions.sh) before submitting your PR.

## Frequently Asked Questions

### What branch should I target for pull requests?

Always target the `beta` branch. The `beta` branch serves as the active development line for the Unity MCP project, while `main` typically represents the latest stable release. The maintainers will merge `beta` into `main` when preparing releases.

### Do I need to implement both Python and C# code for every contribution?

Yes. The architecture requires **domain symmetry**—every Python tool in `Server/src/services/tools/` must have a corresponding C# implementation in `MCPForUnity/Editor/Tools/`. The Python layer handles MCP protocol communication, while the C# layer executes the actual Unity Editor operations.

### How do I handle Unity version compatibility?

Place version-specific compatibility code in `MCPForUnity/Runtime/Helpers/` using the existing shim pattern (e.g., `Unity*Compat.cs` files). The repository maintains support for multiple Unity versions, and the [`tools/check-unity-versions.sh`](https://github.com/CoplayDev/unity-mcp/blob/main/tools/check-unity-versions.sh) script validates compilation across these versions.

### What testing framework does the project use?

The Python codebase uses **pytest** with `pytest-asyncio` for asynchronous test support, located in `Server/tests/`. The Unity codebase uses **NUnit** for Edit-mode and Play-mode tests, located in `TestProjects/UnityMCPTests/Assets/Tests/`. Both test suites must pass before a pull request can be merged.