Skip to content

Commit 323ce2e

Browse files
authored
docs: add MCP server README (#1210)
* docs: add MCP server README Documents the MCP server's purpose as a thin JSON-RPC adapter over gRPC, transport modes (stdio/SSE), environment variables, OAuth 2.1 configuration, Claude Desktop setup, available tools by category, resources, prompts, and local development with Tilt. * docs: fix Go version and add MERIDIAN_API_KEY to MCP server README Address bot review feedback: - Update Go prerequisite from 1.22+ to 1.26+ to match go.mod - Add MERIDIAN_API_KEY to environment variables table (required bearer token) - Include MERIDIAN_API_KEY in Claude Desktop config and standalone examples --------- Co-authored-by: Ben Coombs <bjcoombs@users.noreply.github.com>
1 parent 5c72c18 commit 323ce2e

1 file changed

Lines changed: 328 additions & 0 deletions

File tree

services/mcp-server/README.md

Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
---
2+
name: mcp-server
3+
description: Model Context Protocol server that exposes Meridian backend services to LLM clients via a thin JSON-RPC adapter over gRPC
4+
triggers:
5+
- Connecting Claude or another LLM client to Meridian
6+
- Querying financial positions, postings, or saga causation trees from an AI assistant
7+
- Validating, planning, and applying economy manifests through a conversational interface
8+
- Simulating CEL expressions, saga scripts, or valuation dry-runs before deployment
9+
- Configuring Claude Desktop for local Meridian development
10+
instructions: |
11+
MCP Server is a thin JSON-RPC adapter that exposes Meridian's gRPC services to LLM clients
12+
using the Model Context Protocol (MCP 2024-11-05).
13+
14+
Key patterns:
15+
- Transport agnostic: stdio for CLI tools (Claude Desktop), SSE for browser-based clients
16+
- Tool categories: Read (no side effects), Simulate (dry-run), Write (state mutation)
17+
- Plan-before-apply safety: meridian_manifest_plan must precede meridian_manifest_apply
18+
- OAuth 2.1 with PKCE: optional, enabled via MCP_OAUTH_ENABLED=true for SSE mode
19+
- All logs go to stderr; stdout is reserved for the JSON-RPC protocol (stdio mode)
20+
---
21+
22+
# MCP Server
23+
24+
Thin JSON-RPC adapter that exposes Meridian's backend services to LLM clients via the
25+
[Model Context Protocol](https://spec.modelcontextprotocol.io/) (MCP 2024-11-05).
26+
27+
## Overview
28+
29+
| Attribute | Value |
30+
|-----------|-------|
31+
| **Type** | Infrastructure (API Gateway) |
32+
| **Language** | Go |
33+
| **Protocol** | MCP 2024-11-05 |
34+
| **Transports** | stdio, SSE |
35+
| **Auth** | OAuth 2.1 with PKCE (optional, SSE only) |
36+
| **Standalone** | No (requires Meridian backend services via `MERIDIAN_API_URL`) |
37+
38+
## Architecture
39+
40+
The MCP server is a stateless adapter. It translates MCP JSON-RPC calls into gRPC requests
41+
against Meridian's backend services and returns structured results suitable for LLM consumption.
42+
43+
```mermaid
44+
flowchart TB
45+
subgraph "MCP Clients"
46+
CD[Claude Desktop]
47+
CB[Claude.ai / Browser]
48+
CLI[CLI Tools]
49+
end
50+
51+
subgraph "MCP Server"
52+
ST[stdio Transport]
53+
SE[SSE Transport]
54+
TH[Tool Handlers]
55+
RH[Resource Handlers]
56+
PH[Prompt Handlers]
57+
OA[OAuth 2.1 PKCE]
58+
end
59+
60+
subgraph "Meridian Backend"
61+
CP[Control Plane]
62+
RD[Reference Data]
63+
PK[Position Keeping]
64+
FA[Financial Accounting]
65+
SA[Saga Admin]
66+
RC[Reconciliation]
67+
MI[Market Information]
68+
end
69+
70+
CD -->|JSON-RPC| ST
71+
CLI -->|JSON-RPC| ST
72+
CB -->|JSON-RPC + Bearer| SE
73+
SE <--> OA
74+
75+
ST --> TH
76+
SE --> TH
77+
TH --> RH
78+
TH --> PH
79+
80+
TH -->|gRPC| CP
81+
TH -->|gRPC| RD
82+
TH -->|gRPC| PK
83+
TH -->|gRPC| FA
84+
TH -->|gRPC| SA
85+
TH -->|gRPC| RC
86+
TH -->|gRPC| MI
87+
```
88+
89+
## Transport Modes
90+
91+
### stdio (default)
92+
93+
Used by Claude Desktop and CLI tools. The server reads JSON-RPC requests from stdin and writes
94+
responses to stdout. Logs are written to stderr to avoid corrupting the protocol channel.
95+
96+
```bash
97+
MCP_TRANSPORT=stdio ./mcp-server
98+
```
99+
100+
### SSE
101+
102+
Used by browser-based clients and network-accessible deployments. The server exposes two HTTP
103+
endpoints:
104+
105+
| Endpoint | Purpose |
106+
|----------|---------|
107+
| `GET /sse` | Establishes the SSE stream for server-to-client messages |
108+
| `POST /message` | Receives client JSON-RPC requests |
109+
110+
```bash
111+
MCP_TRANSPORT=sse MCP_SSE_PORT=8090 ./mcp-server
112+
```
113+
114+
## Environment Variables
115+
116+
| Variable | Default | Purpose |
117+
|----------|---------|---------|
118+
| `MCP_TRANSPORT` | `stdio` | Transport mode: `stdio` or `sse` |
119+
| `MCP_SSE_PORT` | `8090` | HTTP port when using SSE transport |
120+
| `MCP_SERVER_NAME` | `meridian-mcp` | Server name reported in MCP initialize response |
121+
| `MCP_BASE_URL` | `http://localhost:8090` | Base URL for OAuth redirect URIs (SSE mode) |
122+
| `MCP_OAUTH_ENABLED` | `false` | Enable OAuth 2.1 PKCE flow for SSE transport |
123+
| `MCP_OAUTH_CLIENT_ID` | `meridian-mcp` | OAuth client ID advertised to clients |
124+
| `MCP_OAUTH_REDIRECT_URI` | `{MCP_BASE_URL}/oauth/callback` | OAuth redirect URI |
125+
| `MERIDIAN_API_URL` | - | gRPC address of the Meridian gateway (e.g., `localhost:9090`) |
126+
| `MERIDIAN_API_KEY` | - | Bearer token sent in the `Authorization` header on all outgoing gRPC calls |
127+
| `LOG_LEVEL` | `info` | Log verbosity: `debug`, `info`, `warn`, `error` |
128+
129+
## OAuth 2.1 Configuration
130+
131+
OAuth 2.1 with PKCE is optional and only applies to the SSE transport. When enabled, the server
132+
exposes authorization and token endpoints and requires clients to present a bearer token on the
133+
`/sse` and `/message` endpoints.
134+
135+
Example configuration for a production SSE deployment:
136+
137+
```bash
138+
MCP_TRANSPORT=sse
139+
MCP_SSE_PORT=8090
140+
MCP_BASE_URL=https://mcp.example.com
141+
MCP_OAUTH_ENABLED=true
142+
MCP_OAUTH_CLIENT_ID=my-mcp-client
143+
MCP_OAUTH_REDIRECT_URI=https://mcp.example.com/oauth/callback
144+
```
145+
146+
OAuth endpoints exposed when `MCP_OAUTH_ENABLED=true`:
147+
148+
| Endpoint | Purpose |
149+
|----------|---------|
150+
| `GET /oauth/authorize` | Authorization endpoint (PKCE challenge) |
151+
| `POST /oauth/token` | Token endpoint (code exchange) |
152+
153+
The current implementation ships a passthrough token issuer and validator suitable for development.
154+
For production, configure a real JWT signer and validator.
155+
156+
## Claude Desktop Configuration
157+
158+
### stdio mode (recommended for local development)
159+
160+
Add the following to your Claude Desktop configuration file
161+
(`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
162+
163+
```json
164+
{
165+
"mcpServers": {
166+
"meridian": {
167+
"command": "/path/to/mcp-server",
168+
"env": {
169+
"MCP_TRANSPORT": "stdio",
170+
"MERIDIAN_API_URL": "localhost:9090",
171+
"MERIDIAN_API_KEY": "pk_your_tenant_api_key",
172+
"LOG_LEVEL": "info"
173+
}
174+
}
175+
}
176+
}
177+
```
178+
179+
### SSE mode (for network-accessible deployments)
180+
181+
```json
182+
{
183+
"mcpServers": {
184+
"meridian": {
185+
"url": "http://localhost:8090/sse"
186+
}
187+
}
188+
}
189+
```
190+
191+
## Available Tools
192+
193+
Tools are grouped into three categories:
194+
195+
- **Read** -- Query state without side effects
196+
- **Simulate** -- Compute or preview without persisting changes
197+
- **Write** -- Mutate state (requires explicit confirmation in most clients)
198+
199+
### Read Tools
200+
201+
| Tool | Description |
202+
|------|-------------|
203+
| `meridian_economy_structure` | Returns a hierarchical summary of the tenant's economy: instruments, account types, valuation rules, sagas, and payment rails |
204+
| `meridian_instruments_list` | Lists instrument definitions with optional status filter (ACTIVE, DRAFT, DEPRECATED) |
205+
| `meridian_instrument_describe` | Returns full details for a specific instrument by code, including CEL validation expressions |
206+
| `meridian_sagas_list` | Lists saga workflow definitions with optional status filter and system saga exclusion |
207+
| `meridian_saga_describe` | Returns full details for a saga including its Starlark script; lookup by UUID or name |
208+
| `meridian_handlers_describe` | Returns saga triggers and account type CEL policies from the current manifest |
209+
| `meridian_market_data_query` | Lists market data sets or queries observations for a specific dataset code |
210+
| `meridian_manifest_history` | Paginated manifest version history with apply status and timestamps |
211+
| `meridian_causation_tree` | Fetches the full parent→child saga causation tree for a root saga ID |
212+
| `meridian_positions_query` | Queries financial position logs with optional account filtering |
213+
| `meridian_postings_query` | Queries ledger postings with optional date range and account filtering |
214+
| `meridian_saga_executions` | Queries saga definitions and execution status filtered by state |
215+
| `meridian_reconciliation_status` | Queries reconciliation cycle status and variance mismatches |
216+
217+
### Simulate Tools
218+
219+
| Tool | Description |
220+
|------|-------------|
221+
| `meridian_manifest_validate` | Validates a manifest JSON without applying it; returns errors with paths and suggestions |
222+
| `meridian_manifest_diff` | Compares two manifests and returns a structured change summary by section |
223+
| `meridian_cel_evaluate` | Evaluates a CEL expression against a named environment without persisting state |
224+
| `meridian_valuation_simulate` | Dry-runs a valuation to convert an input quantity to a valued amount; returns full calculation path |
225+
| `meridian_saga_simulate` | Dry-runs a Starlark saga script with all service calls stubbed; returns step-by-step execution trace |
226+
227+
### Write Tools
228+
229+
| Tool | Description |
230+
|------|-------------|
231+
| `meridian_manifest_plan` | Dry-runs a manifest apply, stores the result, and returns a `plan_hash` for use with apply |
232+
| `meridian_manifest_apply` | Applies a manifest that has been previously planned; requires the `plan_hash` from plan |
233+
234+
The plan-before-apply workflow enforces a safety gate: `meridian_manifest_apply` rejects any
235+
manifest that was not first processed by `meridian_manifest_plan` in the same session.
236+
237+
## Resources
238+
239+
Resources provide context that the LLM can load on demand. Access them via `resources/read` with
240+
the resource URI.
241+
242+
| URI | Name | Description |
243+
|-----|------|-------------|
244+
| `meridian://manifest/current` | Current Economy Manifest | The active economy manifest for the current tenant in YAML format |
245+
| `meridian://docs/starlark-guide` | Starlark Saga Development Guide | Reference guide for writing Starlark saga scripts, including service modules, CEL patterns, and compensation patterns |
246+
| `meridian://docs/cel-reference` | CEL Expression Reference | Reference guide for Common Expression Language used in validation rules, bucketing expressions, and precondition checks |
247+
248+
The `meridian://manifest/current` resource requires `MERIDIAN_API_URL` to be configured. If the
249+
client is not configured, a placeholder message is returned.
250+
251+
The Starlark and CEL documentation are embedded at compile time and available without a backend
252+
connection.
253+
254+
## Prompts
255+
256+
Prompts are guided workflow starters that prime the LLM for a specific task. Use `prompts/get`
257+
with the prompt name and any required arguments.
258+
259+
| Prompt | Arguments | Description |
260+
|--------|-----------|-------------|
261+
| `design-economy` || Guided manifest creation workflow. Asks clarifying questions about instruments, account types, sagas, and valuation rules, then generates a complete manifest |
262+
| `audit-transaction` | `transaction_id` (required) | Investigates a transaction's causation tree: originating saga, position movements, journal entries, and compensation actions |
263+
| `simulate-change` | `change_description` (required) | Tests a proposed manifest change before applying; analyses impact on sagas, instruments, and account types |
264+
| `debug-saga` | `saga_id` (required) | Diagnoses a failed or stuck saga: execution log, failing step, compensation status, and remediation suggestions |
265+
266+
## Local Development
267+
268+
The MCP server is included in the Tilt local development stack.
269+
270+
### Prerequisites
271+
272+
- A running Meridian local cluster (see root `Tiltfile`)
273+
- Go 1.26+ for building locally outside of Tilt
274+
275+
### Running with Tilt
276+
277+
Start the full Meridian stack:
278+
279+
```bash
280+
cd ~/dev/github.com/meridianhub/meridian/meridian-main
281+
tilt up
282+
```
283+
284+
The MCP server starts alongside the other services and connects to the local Meridian gateway.
285+
286+
### Running standalone (stdio mode)
287+
288+
Build and run directly against a running local cluster:
289+
290+
```bash
291+
# From repo root
292+
go build -o /tmp/meridian-mcp ./services/mcp-server/cmd
293+
294+
# Run in stdio mode
295+
MERIDIAN_API_URL=localhost:9090 \
296+
MERIDIAN_API_KEY=pk_your_tenant_api_key \
297+
LOG_LEVEL=debug \
298+
/tmp/meridian-mcp
299+
```
300+
301+
### Running standalone (SSE mode)
302+
303+
```bash
304+
MCP_TRANSPORT=sse \
305+
MCP_SSE_PORT=8090 \
306+
MERIDIAN_API_URL=localhost:9090 \
307+
MERIDIAN_API_KEY=pk_your_tenant_api_key \
308+
LOG_LEVEL=debug \
309+
/tmp/meridian-mcp
310+
```
311+
312+
Then connect Claude Desktop using the SSE configuration above, or test with curl:
313+
314+
```bash
315+
# Open SSE stream
316+
curl -N http://localhost:8090/sse
317+
318+
# Send a tools/list request (in a separate terminal)
319+
curl -X POST http://localhost:8090/message \
320+
-H 'Content-Type: application/json' \
321+
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
322+
```
323+
324+
## References
325+
326+
- [Services Architecture](../README.md)
327+
- [Control Plane Service](../control-plane/README.md)
328+
- [MCP Protocol Specification](https://spec.modelcontextprotocol.io/)

0 commit comments

Comments
 (0)