Skip to main content
Glama
README.md
# General Decision MCP

[中文指南](README_CN.md)

An advisory-only MCP server for deployment/security decisions, coding-loop control and plan comparison. It calls the **native System One API**, not Chat Completions. One implementation serves stdio and stateless Streamable HTTP.

## Architecture and implementation choice

Client → General Decision MCP → CLIProxy `/v1/systemone` → configured decision provider. The existing gateway handles provider credentials and routing; this service holds only its downstream key. Alternatively, `typesafe` mode calls the official native endpoint directly.

This is a small source derivative of pinned MIT references [jkudish/jev-mcp](https://github.com/jkudish/jev-mcp/tree/d119eb5c3555d1daff5e6923d2d3cf8225a8d796) and [burnigtm/jev-mcp](https://github.com/burnigtm/jev-mcp/tree/521d76d01183f2230ec84ec5834413cb408ca85a). It reuses pure tool/question/policy and transport-boundary patterns, not either complete runtime. See [notices](THIRD_PARTY_NOTICES.md).

The official MCP SDK handles protocol negotiation. Unlike the unmodified reference implementation, this package has dependency-injected providers, explicit output schemas, native `structuredContent`, no inference deadline, no automatic retry, and mandatory separate HTTP authentication. The TypeSafe SDK's mandatory positive request timeout is why the native transport uses Node HTTP/HTTPS rather than that SDK. No shell, file-reading, arbitrary URL fetching, feedback storage or infrastructure execution tool exists.

This standalone repository runs independently of CLIProxy's Go source tree. It is **not** a gateway-hosted `/v0/mcp/servers/general-decision` endpoint and does not modify existing clients or production configuration. Its repository is https://github.com/Magnetic015/GeneralDecisionMCP; `private: true` in package.json only prevents accidental npm publication.

## Install and start

Requires Node >=22. Use the repository-approved runtime manager if installing Node. From this package directory:

```bash
npm ci --ignore-scripts --registry=https://registry.npmjs.org
```

```bash
npm run build
```

Create a private `.env` using [.env.example](.env.example). Set the **full** native endpoint and gateway downstream key. Do not copy placeholder values unchanged or commit real keys. On POSIX keep secret files mode 0600; on Windows restrict their ACL to the service/user account.

```dotenv
JEV_PROVIDER=compatible
JEV_API_BASE_URL=https://gateway.example.com/v1/systemone
JEV_API_KEY=REPLACE_WITH_GATEWAY_KEY
JEV_MODEL=jev-latest
JEV_MCP_TRANSPORT=stdio
```

The endpoint is sent exactly as configured; nothing is appended. `JEV_MODEL` and legacy `JEV_MCP_MODEL` are accepted, but conflicting values fail startup. A configured provider never changes because an unrelated credential exists in the environment. Unsupported providers fail explicitly.

Local stdio:

```bash
node --env-file=.env dist/index.js
```

HTTP mode requires an independent random token of at least 32 characters:

```dotenv
DECISION_HTTP_HOST=127.0.0.1
DECISION_HTTP_PORT=8737
DECISION_MCP_TOKEN=REPLACE_WITH_A_SEPARATE_LONG_RANDOM_TOKEN
DECISION_MAX_IN_FLIGHT=4
```

```bash
node --env-file=.env dist/index.js --http
```

`--http` overrides `JEV_MCP_TRANSPORT`. `/mcp` accepts authenticated POST requests; `/health` reports only liveness, not upstream access. This is static header-based Bearer authentication for controlled clients, not an OAuth authorization server. URL/path/query tokens are rejected. The upstream key and MCP token must differ.

For non-loopback/container binds, set `DECISION_HTTP_ALLOWED_HOSTS` to exact client-facing authorities (including a non-default port). Requests with an Origin header must match `DECISION_HTTP_ALLOWED_ORIGINS` (comma-separated exact origins); without an override, only the local service origin is allowed for loopback binds. Client applications without Origin are accepted after authentication. Do not depend on CORS as authentication or trust forwarded headers implicitly.

Cancellation follows the original HTTP request's abort/disconnect signal. Because this endpoint is stateless, separate legacy `notifications/cancelled` POSTs cannot identify an earlier client's stream safely: they are explicitly rejected (409, or 429 while saturated), not silently acknowledged. A client that only sends those notifications should use stdio instead; merely sending a notification does not cancel the original inference. HTTP batch calls are rejected. A shared call-level limiter also bounds stdio inference, and duplicate active stdio IDs abort the original work.

Pre-authentication sockets are capped at `max(16, 4 * DECISION_MAX_IN_FLIGHT)`. There is no inference deadline or inbound receive timer in this service. Slow authenticated callers can occupy bounded slots; a public deployment therefore requires a trusted ingress with header/body receive limits and connection/rate controls. Do not expose this listener directly to the Internet.

Each credential accepts a mutually exclusive `_FILE` source: `JEV_API_KEY_FILE`, `TYPESAFE_API_KEY_FILE`, `DECISION_MCP_TOKEN_FILE`. Files are read at startup only, must be regular non-symlinks, at most 8192 bytes, and private on POSIX. An HTTP token is not required for stdio.

### Client registration

Copy/merge one selected template; do not overwrite existing configuration:

| Client | Local | HTTP | Destination |
|---|---|---|---|
| Code client | [stdio](examples/code-client.stdio.json) | [HTTP](examples/code-client.http.json) | Project `.mcp.json` or the appropriate user configuration |
| Cursor | [stdio](examples/cursor.stdio.json) | [HTTP](examples/cursor.http.json) | `.cursor/mcp.json` |
| Codex | [stdio](examples/codex.stdio.toml) | [HTTP](examples/codex.http.toml) | User `config.toml` or trusted-project `.codex/config.toml` |
| OpenCode | [stdio](examples/opencode.stdio.json) | [HTTP](examples/opencode.http.json) | `opencode.json`; templates follow the current `mcp.servers` schema |

Replace the Windows paths for your checkout. Local examples explicitly use Node's `--env-file`, not assumed client interpolation. Remote examples intentionally use different environment syntax: `${NAME}` for Code client, `${env:NAME}` for Cursor, `{env:NAME}` for OpenCode, and `bearer_token_env_var` for Codex. These variables must be visible to the client process. `DECISION_MCP_URL` is the deployed HTTPS MCP `/mcp` URL, not the native inference endpoint. Register either stdio or HTTP for one instance to avoid duplicate tool catalogs.

### Optional container

[compose.example.yaml](compose.example.yaml) is opt-in and is not automatically started. It publishes only `127.0.0.1:8737`, runs non-root with a read-only root filesystem and no host repository/Docker socket. Its two file secrets must be readable by the container service UID (default 1000) and retain private permissions; Compose file-backed secrets preserve host ownership/mode, so prepare them accordingly. Override the container user when the deployment requires a different UID/GID. The host endpoint and its port must match the allowed-host setting.

TLS termination, remote routing, production key provisioning and firewall changes require a separate deployment decision. No public endpoint is provisioned by this repository change. The example image is pinned; rebuild and review it before production use.

## Tools and output

Nine tools are registered. No aliases or upstream tools outside this list are implied:

| Tool | Main required fields | Derived summary |
|---|---|---|
| `jev_coding_loop` | task, observation, evidence | next step, model capability tier, focus, completion/risk signals; never invokes another model |
| `jev_review` | request, diff, evidence | independent correctness/spec/test-gap/blast-radius rubrics |
| `jev_gate` | request, diff, claims, evidence | patch review **and** independent claim/subject checks |
| `jev_risk` | request, change_type, environment, change, evidence | severity, blast radius, rollback support, handling and change-specific concerns |
| `jev_verify` | claims, evidence | supported/contradicted/unknown, subject match and original claim IDs |
| `jev_screen` | purpose, items | injection/relevance/substance probabilities; no sanitization claim |
| `jev_classify` | purpose, items, classes | class probabilities and an unavoidable investigate escape |
| `jev_rank` | task, priorities, candidates, evidence | **relative Choice preference distribution**, not independent relevance scores; dependency-valid order plus violations |
| `jev_decide` | decision, evidence (string), priorities, candidates | bounded alternatives and per-requirement checks; fixed ask_user/investigate/none escapes |

Use [all nine calls](examples/tool-calls.json) and the advertised `tools/list` schemas for exact nested fields. Evidence/items/claims use `{id,text}`; candidates/classes use `{id,description}`. Optional `scope` defaults to unknown on every tool. For `jev_risk`, environment and consequence scope are independent: staging/development never imply local, and `scope=local` cannot override a production/security floor. `evidence_complete` defaults to false. Caller-provided facts are claims, never independent proof or authorization. Unknown input fields cannot override endpoint, model, thresholds or credentials.

Every result has `schema_version`, `status`, `tool`, `provider`, `requested_model`, actual `model` (nullable), validated native `answers`, `policy`, `evidence`, `usage` (nullable), and tool-specific `summary`. Opaque native question IDs are mapped to meaningful labels/IDs by `summary`. The JSON text fallback equals `structuredContent`.

`policy.advisory_only` is always true and `policy.authorization` is always `not_granted`. `requires_human=false` is a low-risk advisory classification, **not permission to execute**. Provider/tool-handler failures have `isError:true`, a fixed safe error code, and human review required. SDK-level argument/protocol validation may instead return text-only `isError` or a JSON-RPC error; clients must check errors before accessing structured data. Upstream error bodies, credentials and stack traces are not reflected.

### Confidence and operational safeguards

- Native Choice confidence describes distribution concentration, not correctness: for Typesafe, `(pmax - 1/n) / (1 - 1/n)`. It is not the top-two margin. Both the native value and original distribution are retained.
- Score remains on its original ordered `0..n-1` scale, with exact legend and expected-value consistency checks.
- Noul contains only `p`; no fake native confidence is added. Missing confidence forces review where the policy needs it. Missing usage is null, never fabricated as zero.
- Choice advisory floors are fixed: native confidence >=0.85, winning probability >=0.85 and top-two difference >=0.20. Rubrics pass independently; favorable dimensions never average away a dangerous one. These are conservative starting rules, not measured accuracy guarantees.
- Production scope, security operations, GeoIP restrictions, fail2ban, SSH, new public exposure, irreversible changes and missing critical evidence require human review regardless of probability.
- Firewall reviews include IPv4/IPv6, forwarding/return traffic, administrative access, dependencies and tested rollback. Fail2ban reviews include trustworthy client IPs, proxies/shared exits, containers, matching breadth and bans/whitelists. GeoIP reviews include database staleness, legitimate users, VPN/CDN/shared addresses and rotating IPv6 prefixes; location is not maliciousness.
- Coding-loop facts can override a model proposal: repeated failures cannot produce another blind retry; failed/unverified tests cannot support stop-as-complete. Proposed capability tiers are labels, not actual model selection.
- Screening does not make untrusted content trusted. The server never runs instructions contained in logs, diffs, documents or option descriptions.
- Before operational use, evaluate false acceptance, false rejection and evidence coverage on labeled local cases. Pin an actual model version if reproducibility matters; `jev-latest` can change upstream behavior.

## Provider extensions

Implemented today:

- `compatible`: full native endpoint, `JEV_API_KEY`, `JEV_MODEL`. Works with a gateway or self-hosted service that actually implements the System One contract.
- `typesafe`: fixed `https://api.typesafe.ai/v1/systemone`, `TYPESAFE_API_KEY` or `_FILE`. Uses the same timeout-free JSON transport, not the SDK's request timer.

OpenRouter's documented native Decisions API is `https://openrouter.ai/api/alpha/decisions`, not Chat Completions. A `compatible` profile can point there with its own key and a native model such as `~typesafe/jev-latest`; this routing has not been live-tested here. Generic JSON-generating chat models do not acquire native calibrated probabilities merely by imitating this schema.

Cloudflare Clef **is not implemented in this release**; selecting `cloudflare` fails rather than silently routing somewhere else. A future adapter must map its per-model endpoint `/client/v4/accounts/<account>/ai/run/@cf/cloudflare/clef` (or `clef-flash`), bearer token and the documented short body selector `clef`/`clef-flash`, unwrap the actual v4 response, then call the existing validator. Do not copy the reference's `typesafe/` slug prefix. See [extension contract](examples/provider-contracts.json). Validate its question/context limits and instructions; never silently truncate evidence.

To compare providers, run two named MCP instances with separate environment/secret files. Their models, keys and endpoint state are isolated. Invoke both only on an explicit request. Keep disagreement visible and escalate rather than average probabilities or claim consensus proves safety.

## Verification and limits

```bash
npm run typecheck
```

```bash
npm test
```

Tests use only loopback fixture providers and official MCP clients. They cover all primitives, schema failures, policy floors, exact URL/auth mapping, redirects/no retries, request cancellation, body/concurrency limits, stateless HTTP, stdio, and absence of inference during initialize/list. Native request body is capped at 256 KiB, response at 1 MiB, question count at 64. Oversized input is rejected, not truncated. This package imposes no inference timeout; callers must cancel abandoned work. Gateway policies may independently retry or time out and should be assessed separately.

No live inference, client installation or production deployment is part of the test suite. Container packaging is an optional example and needs its own build/run verification on the target host. Existing gateway MCP tests/build remain separate.

## References

- [TypeSafe confidence semantics](https://docs.typesafe.ai/confidence.md)
- [Official MCP TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
- [Cloudflare Clef](https://developers.cloudflare.com/workers-ai/models/clef/)
- [OpenRouter Jev Decisions](https://openrouter.ai/blog/tutorials/how-to-use-jev/)
- [Code client MCP](https://modelcontextprotocol.io)
- [Cursor MCP](https://cursor.com/docs/context/mcp)
- [Codex MCP](https://learn.chatgpt.com/docs/extend/mcp?surface=cli)
- [OpenCode MCP](https://opencode.ai/docs/mcp-servers/)

TDQS

A3.6/5.0

Scored across 9 tools

Disambiguation4/5

Each tool covers a distinct decision-support function (screen, classify, rank, verify, review, gate, risk, decide, coding loop), and the descriptions clarify the boundaries fairly well. The main friction is the review/gate pair and the verify/decide/rank cluster, which sit close together conceptually and require reading descriptions to separate.

Naming Consistency4/5

All names share a consistent jev_ prefix with short descriptive suffixes, which is highly predictable. Minor deviation: jev_coding_loop is a compound noun phrase while the rest are single verbs, but it remains readable and unlikely to confuse.

Tool Count5/5

Nine tools is well within a comfortable scope for a decision-support suite, and each maps to a different stage of the pipeline rather than duplicating another. No tool appears redundant or trivially filler.

Completeness4/5

The surface covers the full advisory pipeline from screening and classification through ranking, verification, review, gating and final decision, which is solid coverage for the stated purpose. Minor gaps exist around recording/auditing decisions or retrieving prior judgments, but agents can work around these by passing context in.

Maintenance

ActivityMaintained
ResponsivenessOutdated data