> ## Documentation Index
> Fetch the complete documentation index at: https://docs.neuro-tech.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Build an MCP server package

> Add an OAuth-protected MCP tool to a Neuron with public NuGet packages

This guide extends the [Neuron package quickstart](/neuron-development/quickstart) with one read-only MCP tool. It does not require the Neuron, Neuro-Ledger, or IoTBroker source repositories.

## 1. Add the MCP packages

From the class-library project created in the package quickstart:

```bash theme={null}
dotnet add package Waher.Networking.HTTP.Mcp --version 1.1.0
dotnet add package Waher.Networking.HTTP.OAuth --version 1.0.1
```

Keep the existing `Waher.IoTGateway` reference. Match all package versions to the Neuron you will test against before deployment.

## 2. Add the server and module

```csharp theme={null}
using System;
using System.Threading.Tasks;
using Waher.IoTGateway;
using Waher.Networking.HTTP.JsonRpc;
using Waher.Networking.HTTP.Mcp;
using Waher.Networking.HTTP.Mcp.Model.Attributes;
using Waher.Networking.HTTP.OAuth;
using Waher.Networking.HTTP.OAuth.MetaData;
using Waher.Networking.Sniffers;
using Waher.Runtime.Inventory;

[OAuthResourceName("Example MCP Server")]
[McpScopeRoot("MCP:Example")]
public sealed class ExampleMcpServer : HttpMcpServerResource
{
    private const string ReadPrivilege =
        "OAUTH.Scope.MCP.Example.Tools.Read";

    public ExampleMcpServer(string resourceName, ISnifferSet? sniffers)
        : base(
            resourceName,
            "Example",
            "Example",
            "1.0.0",
            "Example Neuron MCP tools.",
            GetDefaultIcons(),
            null,
            "Use these tools only for approved example data.",
            sniffers)
    {
    }

    [McpServerTool(
        "Read Value",
        "Reads one value without changing state.",
        "",
        false, // can modify
        false, // can destroy
        true,  // idempotent
        false  // open-world access
    )]
    [RequiredPrivilege(ReadPrivilege)]
    public Task<string> ReadValue(
        [McpStringParameter("Key", "Value key.", 1, 128)] string key)
    {
        return Task.FromResult(key);
    }
}

[Singleton]
public sealed class ExampleMcpModule : IModule
{
    private ExampleMcpServer? server;

    public Task Start()
    {
        if (Gateway.HttpServer is null)
            throw new InvalidOperationException("The Neuron HTTP server is unavailable.");

        this.server = new ExampleMcpServer("/MCP/Example", null);
        Gateway.HttpServer.Register(this.server);
        return Task.CompletedTask;
    }

    public Task Stop()
    {
        if (this.server != null && Gateway.HttpServer != null)
            Gateway.HttpServer.Unregister(this.server);

        this.server = null;
        return Task.CompletedTask;
    }
}
```

The example targets `netstandard2.1` and has been compiled with `Waher.IoTGateway` 3.10.2, MCP 1.1.0, and OAuth 1.0.1.

## 3. Build and package

```bash theme={null}
dotnet build --configuration Release
```

Add the output assembly to the same module manifest format used in the [package quickstart](/neuron-development/quickstart), then build and install the package.

## 4. Grant and test access

Create a role containing:

```text theme={null}
OAUTH.Scope.MCP.Example.Tools.Read
```

Connect Codex to:

```text theme={null}
https://<NEURON_HOST>/MCP/Example
```

Request the scope `MCP:Example:Tools:Read`, then call **Read Value**. Confirm that removing the privilege causes the tool call to be rejected.

## Before adding a write tool

* Give every operation its own privilege leaf.
* Describe the real side effect in the title and description.
* Set modification, destruction, idempotency, and open-world annotations accurately.
* Bound every input and validate it again in the method.
* Log the actor, target, and outcome without logging secrets.
* Test allowed, denied, invalid, repeated, and partial-failure calls.
