yarrowdalegraph
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@yarrowdalegraphScore this graph of providers and accounts for fraud risk."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
yarrowdalegraph
Graph-based fraud propagation scoring for Elmsworth Diagnostics (Project
Yarrowdale). It runs as an MCP server that exposes one tool, score_graph, over
JSON-RPC 2.0 on stdio.
What it does
Clinical-diagnostics fraud is rarely visible in a single entity. A colluding provider, the billing accounts it controls, the devices those accounts log in from, and downstream referrers form a connected structure. Yarrowdale models that structure as a graph and diffuses fraud risk across it.
The pipeline is:
Build an entity graph: nodes are providers, patients, accounts, devices and claims; edges are observed relationships with a strength weight. Analysts can attach a
seedin[0,1]to any node (a confirmed-fraud entity is1).Obtain a per-node prior risk from a graph-ML model via the
RiskPriorProviderinterface.Propagate those priors across the graph with a personalised-PageRank-style diffusion until convergence, producing a final risk score per node.
The hard constraint: deterministic fallback
Scoring must keep working when the model is unavailable. That is not handled by
a try/catch bolted on at the edge — it drives the architecture:
The model is reached only through
RiskPriorProvider(src/providers/base.ts). Its sole job is to turn a graph into prior scores.FraudScorer(src/scorer.ts) consults the provider behind three guards. Any of them routes to the deterministic path:available()returns false (or throws),priors()throws,priors()returns a map that fails validation (wrong size / out of range).
The fallback (
src/fallback.ts) computes priors from graph structure alone — analyst seeds plus weighted neighbour evidence. No network, no model, fully deterministic.Both paths then run the same propagation algorithm, so a fallback score differs from a model score only in its priors, never in the method. That keeps results explainable to a reviewer.
Every degradation decision is recorded through the
auditcallback, and the result carriespriorSource('model'|'fallback') andfallbackReason.
The test suite runs entirely offline against StubProvider
(src/providers/stub.ts), which also has flags (down, throwOnPriors,
returnIncomplete) to exercise each degradation branch.
Related MCP server: casuallayer-mcp
Layout
src/
types.ts domain model (nodes, edges, params, results)
graph.ts validation + row-normalised transition matrix
propagation.ts core diffusion algorithm
fallback.ts deterministic structural priors
scorer.ts orchestration + degradation + audit
config.ts environment-driven configuration
logger.ts structured JSON logging to stderr
validation.ts untrusted-input parsing + resource limits
server.ts MCP JSON-RPC request handling
main.ts stdio entry point
index.ts public exports
providers/
base.ts RiskPriorProvider interface
stub.ts deterministic offline provider
forced-fallback.ts operator pin to the offline path
tests/ node:test suitesArchitecture
Request flow for a score_graph call:
stdin (JSON-RPC line)
-> main.ts framing, ordering, fatal-error guard
-> server.ts JSON-RPC dispatch, error codes, timing, audit->log
-> validation.ts untrusted JSON -> FraudGraph, resource limits
-> scorer.ts model-or-fallback decision (the degradation point)
-> providers/ model priors, or ...
-> fallback.ts deterministic structural priors
-> propagation.ts diffusion shared by both paths
-> stdout (JSON-RPC line) logs -> stderrThe decisions that had a real alternative are recorded in
docs/adr/: the provider-interface fallback boundary, the shared
propagation path, undirected iterate-don't-invert diffusion, the zero-dependency
MCP transport, and fail-fast configuration.
Requirements
Node 22 or newer. Node runs the TypeScript sources directly, so there is no
build step and no dist/.
Install and test
npm ci
npm testnpm test runs the built-in node --test runner over tests/**/*.test.ts.
Optional type check (requires devDependencies installed):
npm run typecheckRunning the server
npm startThis starts the MCP server on stdio. It reads one JSON-RPC message per line on stdin and writes one response per line on stdout; all logs go to stderr so they never corrupt the protocol stream. A minimal session:
printf '%s\n%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"score_graph","arguments":{"graph":{"nodes":[{"id":"p1","kind":"provider","seed":1},{"id":"acc","kind":"account"}],"edges":[{"source":"p1","target":"acc","weight":2}]}}}}' \
| npm start --silentThe score_graph result is JSON text containing priorSource
(model | fallback), fallbackReason, converged, iterations,
elapsedMs, and a scores map.
Configuration
All configuration is read from the environment at startup. A malformed value is a fatal startup error (exit code 78), never silently ignored.
Variable | Default | Meaning |
|
| Diffusion mixing, strictly in |
|
| Convergence threshold |
|
| Iteration cap |
|
| Reject graphs with more nodes |
|
| Reject graphs with more edges |
|
| Pin scoring to the offline path |
|
|
|
YARROWDALE_FORCE_FALLBACK=true is the operator switch for a model incident: it
routes every request through the deterministic fallback without a redeploy.
Library usage
import { FraudScorer, StubProvider } from './src/index.ts';
const scorer = new FraudScorer(new StubProvider(), {
audit: (e) => console.error(`[audit] ${e.event}: ${e.detail}`),
});
const result = await scorer.score({
nodes: [
{ id: 'p1', kind: 'provider', seed: 1 }, // confirmed fraud
{ id: 'acc', kind: 'account' },
{ id: 'dev', kind: 'device' },
],
edges: [
{ source: 'p1', target: 'acc', weight: 2, relation: 'billing' },
{ source: 'acc', target: 'dev', weight: 1, relation: 'login' },
],
});
console.log(result.priorSource); // 'model' or 'fallback'
console.log(result.scores.get('acc'));Algorithm notes
Propagation solves the fixed point
s = alpha * W s + (1 - alpha) * pwhere W is the row-normalised undirected adjacency and p the prior vector.
For alpha in (0,1) the iteration is a contraction and converges to the
unique solution s = (1 - alpha)(I - alpha W)^{-1} p. Edges are treated as
undirected because collusion evidence is symmetric. We iterate rather than
invert: the graphs are sparse and a few hundred sweeps are cheaper than an
O(n^3) solve. Default alpha = 0.85, tolerance 1e-9, cap 200 iterations.
Known limitations
The learned
RiskPriorProvider(graph neural network) is not yet shipped; only the interface and the deterministic stub are.main.tswires in the stub and will select the model provider from config once it exists. See the TODO insrc/providers/base.ts.The stdio transport handles one message per line and serialises request handling. That is enough for a single MCP client; JSON-RPC batch arrays and concurrent in-flight scoring are not implemented.
Scoring is synchronous and in-memory. A graph near the configured node/edge limits is scored in one event-loop-blocking pass; there is no chunking or backpressure. The limits exist to keep that pass bounded, not to stream.
Propagation treats every relationship type the same once weighted. Distinct edge semantics (a shared device vs. a referral) are captured only through the caller-supplied
weight, not through per-relation propagation rules.
Elmsworth Diagnostics is an illustrative client; this repository is a self-directed reference implementation built to work end to end.
Available Tools
1 toolscore_graphA
Score fraud risk for every entity in a graph by propagating analyst seeds and model priors across relationships. Degrades to a deterministic structural fallback when the model is unavailable.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description explains the core computation and the fallback behavior when the model is unavailable, but it does not disclose side effects, read-only semantics, error behavior, or expected outputs. With no annotations, more behavioral detail would be beneficial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, using two straightforward sentences. It front-loads the primary purpose and follows with the fallback behavior, with no redundant or extraneous information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The complex nested graph schema with node kinds, seeds, edge weights, and attributes is not elaborated. There is also no output schema or description of return values, making the description incomplete for fully understanding how to construct inputs or interpret results.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description does not explain individual parameters such as 'seed', 'attributes', 'weight', or 'relation'. It provides general context about graph relationships but leaves parameter meaning largely to inference.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'Score fraud risk', the resource 'every entity in a graph', and the method 'propagating analyst seeds and model priors across relationships'. It also mentions the deterministic fallback, making the tool's intent unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides clear context for when to use the tool: whenever fraud risk scores are needed for entities in a graph. There are no explicit exclusions, but no sibling tools exist, so the absence of explicit alternative guidance is acceptable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.1.0- First observed
score_graph
TDQS
Scored across 1 tool
With only one tool, there is no potential for overlap or confusion. The tool's purpose is clearly distinct by default.
score_graph is a clear, snake_case verb-noun name that accurately describes the operation. It follows a consistent, predictable convention.
A single tool is thin for a server whose name suggests a graph-oriented domain, though it may be intentionally focused. The one tool is substantive, but users may expect supporting operations.
The tool covers the core fraud-scoring workflow with propagation, seeds, priors, and a fallback. Missing auxiliary operations (e.g., graph management or seed configuration) are likely out of scope.
Maintenance
Related MCP Connectors
Deterministic claim verification with receipts across ~60 domains. No model in the loop.
Diagnose AI workflows for failure, security, and handoff risks — RED/AMBER/GREEN per node.
- causelyOAuthapp.causely
Causal reasoning for reliability: root cause, blast radius, and service health for agents.
Claims-grounded provider, market, and KOL intelligence for healthcare AI agents via Alpha Sophia
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables AI-powered medical information retrieval through FHIR clinical document search and GraphRAG-based exploration of medical entities and relationships. Combines vector search with knowledge graph queries for comprehensive healthcare data analysis.MIT
- AlicenseNot gradedqualityCmaintenanceDeterministic AI liability attribution engine. Scores fault across AI supply-chain participants (deployer, developer, vendor) with tamper-evident certificates and weekly cryptographic anchoring.’26 npm2Apache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables sophisticated reasoning workflows using graph-based representations for AI models.11Apache 2.0
- FlicenseNot gradedqualityDmaintenanceAI-powered fraud detection and investigation platform that exposes tools for querying, scoring, and investigating financial applications using LangGraph, MLflow, and SQLite in-memory.-