Skip to main content

Local development

Running the MCP (Model Context Protocol) Services from source against a local OctoMesh stack on your own machine.

Prerequisites

  • .NET 10 SDK
  • The OctoMesh backend services running locally — see Developer Guide → Getting started and Developer PowerShell for the Start-Octo workflow
  • MongoDB reachable (the default Start-Octo infrastructure exposes it on localhost:27017)
  • octo-cli available — used during one-time tenant bootstrap and as the reference behaviour for new tools

Start the backend services first

The MCP Services calls Identity / Asset / Communication / Bot / Reporting over HTTP. The Start-Octo PowerShell cmdlet starts them natively on the dev machine:

Start-Octo -nonInteractive $true

The ports each service binds locally (used by appsettings.json defaults — see Configuration):

ServiceHTTPS
Assethttps://localhost:5001/
Identityhttps://localhost:5003/
Communicationhttps://localhost:5005/
Bothttps://localhost:5007/
Reportinghttps://localhost:5009/

Stop them with Stop-Octo when you're done.

Run the MCP Services from source

cd octo-mcp-service/src/McpServices
dotnet run --environment Development

In Development mode the server reads appsettings.json + appsettings.Development.json and exposes both transports:

TransportURL
HTTPhttp://localhost:5016/mcp
HTTPShttps://localhost:5017/mcp

The HTTPS port uses the local dev certificate (dotnet dev-certs https --trust if your OS doesn't trust it yet).

The dev server enumerates roughly 187 tool methods at startup. Tail the output to confirm a clean boot — startup errors surface as logged exceptions before the host begins listening.

Register your local server with Claude Code

# HTTP (most common — no cert hassle)
claude mcp add --transport http --scope local octomesh-local http://localhost:5016/mcp

# HTTPS (only if your dev profile binds HTTPS and you trust the dev cert)
claude mcp add --transport http --scope local octomesh-local https://localhost:5017/mcp
// Claude Desktop — claude_desktop_config.json
{
"mcpServers": {
"octomesh-local": {
"type": "http",
"url": "http://localhost:5016/mcp"
}
}
}

Verify:

claude mcp list
# octomesh-local: http://localhost:5016/mcp (HTTP) - ✓ Connected

Restart Claude Code so the tool catalogue is enumerated. Authenticate via interactive OAuth (/mcp → select the server; see below for the dev-certificate caveat) or with the in-band authenticate(tenantId="<your local tenant>") device flow.

Legacy stdio bridge

Earlier versions shipped src/mcp-bridge.js, a Node-based stdio→HTTPS shim required by older Claude Code releases. That shim has been removed. Direct HTTP registration is simpler and supports per-call tenant routing.

Interactive OAuth and the local dev certificate

The interactive OAuth flow (Dynamic Client Registration + Authorization Code + PKCE) makes Claude Code itself call the local Identity Service at https://localhost:5003 — registration, discovery, and token requests all run inside the Claude Code process, not in your browser.

This fails out of the box with unable to verify the first certificate: Claude Code is a Bun-compiled binary with a frozen CA store. It ignores NODE_EXTRA_CA_CERTS for self-signed leaf certificates (the ASP.NET dev cert is a leaf, not a CA) and it does not read the OS trust store either — so neither dotnet dev-certs https --trust nor adding the cert to the macOS keychain helps.

The only working local-dev workaround is disabling TLS verification for the Claude Code process, e.g. via ~/.claude/settings.json:

{
"env": {
"NODE_TLS_REJECT_UNAUTHORIZED": "0"
}
}
Dev machines only

NODE_TLS_REJECT_UNAUTHORIZED=0 disables certificate verification for all TLS connections of the process. Use it only on a local dev machine against localhost services — never against shared or production endpoints (those have real certificates and need no workaround).

The device flow (authenticate tool) does not need this: the browser handles the login (and can trust the dev cert normally), and the token calls run inside the MCP server's .NET process, which uses the machine trust store.

Running the test suite

# Full suite (~400 tests, ~250 ms)
dotnet test Octo.McpServices.sln -c DebugL

# Filter to a single tool class
dotnet test --filter "FullyQualifiedName~TenantManagementToolsTests"

# CI parity (uses Release + private NuGet feed)
dotnet test Octo.McpServices.sln -c Release

The CI build runs in Release against the private NuGet feed ($(nugetPrivateServer)), not DebugL. Mirror this locally when you suspect a config-sensitive failure.

Pitfalls during local-dev

  • CkTypeId format is Name-VersionUint, not SemVer. new CkTypeId("MyType-1") works; new CkTypeId("MyType-1.0.0") throws because the SDK parses the version as uint.
  • OctoObjectId must be a 24-character hex string. Use realistic values like "507f1f77bcf86cd799439011" in tests.
  • Don't reuse SDK clients across requests. The SDK clients cache ServiceUri on first use; sharing one across tenants routes the second call to the wrong tenant. Always go through IOctoServiceClientFactory.Create*Client(tenantId, accessToken) — the *ClientContext.TryBuild helpers do this for you.
  • TreatWarningsAsErrors is on. Missing XML doc on a public member (CS1591) fails the build.

For the full conventions catalogue (response envelope, optimistic locking, file-transfer architecture, aggregation mapper) see CLAUDE.md in the repository.