# JsonRpcEndpointSample

This sample demonstrates a small but realistic operation-oriented API using:

- Minimal APIs instead of controllers
- JSON-RPC 2.0 style requests through `/rpc`
- MCP-style tool discovery/invocation through `/mcp`
- Standard ASP.NET Core dependency injection
- One operation per handler
- Modular Bank and Shipment projects
- Automatic handler discovery
- Automatic method/tool catalog generation
- Automatic JSON schema generation from request/response DTOs
- Swagger/OpenAPI for the HTTP surface

## Startup code

The host startup stays small:

```csharp
builder.Services.AddScoped<IJsonRpcDispatcher, JsonRpcDispatcher>();
builder.Services.AddScoped<IMcpDispatcher, McpDispatcher>();
builder.Services.AddMcpTools(builder.Configuration);
```

There is no per-method registration in `Program.cs`.

## Plugin folder configuration

The plugin folder is configured in `appsettings.json`:

```json
{
  "McpTools": {
    "PluginFolder": "Modules"
  }
}
```

At runtime, `AddMcpTools` loads DLLs from the configured plugin folder, keeps only assemblies marked with `[assembly: RpcAssembly]`, scans `[RpcMethod]` handlers, registers handlers in DI, and creates method/tool metadata.

## Tool module declaration

Each tool module declares itself once:

```csharp
using JsonRpcEndpointSample.Rpc.Abstractions;

[assembly: RpcAssembly("Bank")]
```

## Handler declaration

Each operation handler declares its method once:

```csharp
[RpcMethod(
    "Bank.MakeDeposit",
    Description = "Deposits money into an existing bank account and returns the new balance.",
    IsReadOnly = false)]
[ExposeAsMcpTool]
public sealed class BankMakeDepositHandler
    : RpcRequestHandler<MakeDepositRequest, MakeDepositResponse>
{
    protected override Task<MakeDepositResponse> HandleTypedAsync(MakeDepositRequest request)
    {
        // business logic here
    }
}
```

## DTO schema descriptions

DTO properties can describe themselves for AI/tool metadata:

```csharp
[RpcSchemaProperty("Bank account number receiving the deposit.")]
public string AccountNumber { get; set; } = string.Empty;
```

## Demo build behavior

The host project references Bank and Shipment projects only to build and copy their DLLs into the `Modules` folder:

```xml
<ProjectReference Include="..\JsonRpcEndpointSample.Bank\JsonRpcEndpointSample.Bank.csproj" ReferenceOutputAssembly="false" OutputItemType="McpPlugin" />
<ProjectReference Include="..\JsonRpcEndpointSample.Shipment\JsonRpcEndpointSample.Shipment.csproj" ReferenceOutputAssembly="false" OutputItemType="McpPlugin" />
```

The host code itself does not use Bank or Shipment types.

## Endpoints

- `POST /rpc` executes business JSON-RPC methods directly, such as `Bank.MakeDeposit`.
- `GET /rpc/methods` returns the method catalog.
- `GET /rpc/tools` returns the AI-friendly tool catalog.
- `POST /mcp` supports MCP-style `initialize`, `tools/list`, and `tools/call` methods.
- `/swagger` shows the HTTP endpoints.

## PowerShell examples

Replace the port with the one shown in your console.

List methods:

```powershell
Invoke-RestMethod -Uri "http://localhost:64720/rpc/methods" -Method Get
```

List MCP tools:

```powershell
$response = Invoke-RestMethod -Uri "http://localhost:64720/mcp" -Method Post -ContentType "application/json" -Body '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":"2"}'
$response | ConvertTo-Json -Depth 10
```

Call a tool through MCP:

```powershell
Invoke-RestMethod -Uri "http://localhost:64720/mcp" -Method Post -ContentType "application/json" -Body '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"Bank.MakeDeposit","arguments":{"accountNumber":"A-100","amount":250}},"id":"3"}'
```

Call the same operation through `/rpc`:

```powershell
Invoke-RestMethod -Uri "http://localhost:64720/rpc" -Method Post -ContentType "application/json" -Body '{"jsonrpc":"2.0","method":"Bank.MakeDeposit","params":{"accountNumber":"A-100","amount":250},"id":"1"}'
```


## MCP exposure is opt-in

`[RpcMethod]` registers a handler for the `/rpc` endpoint.

`[ExposeAsMcpTool]` additionally exposes that handler through the MCP `tools/list` and `tools/call` surface.

This allows internal or application-only RPC methods to remain callable through `/rpc` while staying hidden from MCP clients.
