Skip to main content
Glama

decide-mcp

A local MCP server that lets an agent delegate a decision to a configurable model. Send a decision, context, and choices; receive a recommended choice and percentages. The agent decides what to do next.

Defaults to TypeSafe AI Jev through AI Gateway, using AI SDK 7's experimental_evaluate. Supports custom decision policies, multiple bias profiles, automatic profile routing, and individual tools per profile.

Install

Requires Node.js 22+. Add this to an MCP client that supports stdio:

{
  "mcpServers": {
    "decide": {
      "command": "npx",
      "args": ["-y", "decide-mcp@0.1.0"],
      "env": { "AI_GATEWAY_API_KEY": "your-gateway-key" }
    }
  }
}

Or install globally with npm install -g decide-mcp and use decide-mcp as the command. The published package includes the built CLI; users do not need Bun.

Related MCP server: routewise

Develop locally

Requires Bun for development and Node.js 22+ to run the built server.

bun install --frozen-lockfile
bun run build

Add this to an MCP client that supports stdio, replacing the path and credential with your own values:

{
  "mcpServers": {
    "decide": {
      "command": "node",
      "args": ["/absolute/path/decide-mcp/dist/cli.js"],
      "env": { "AI_GATEWAY_API_KEY": "your-gateway-key" }
    }
  }
}

The default needs no configuration file. It uses typesafe-ai/jev. This package runs locally; it is not a hosted MCP endpoint. Agents without stdio MCP support need a separate transport integration.

For configuration, add "--config", "/absolute/path/decide.config.json" to args. Alternatively, set DECIDE_CONFIG to a file path or DECIDE_CONFIG_JSON to inline JSON in the MCP client's environment. File and inline configuration cannot be combined. Relative custom provider modules resolve from the configuration file's directory; inline configuration uses the process working directory.

The server reads environment variables from its MCP process. It does not automatically load .env files. Credentials stay in environment variables; configuration uses names such as apiKeyEnv rather than secret values.

Tool contract

Call decide:

{
  "decision": "Should we release this change now?",
  "context": {
    "tests": "passing",
    "rollback": "available",
    "risk": "Touches a critical payment path; production traffic is currently high."
  },
  "choices": [
    { "id": "ship", "description": "Release immediately" },
    { "id": "wait", "description": "Wait for a lower-traffic window" }
  ]
}

Illustrative response (actual scores depend on the model):

{
  "selectedChoice": "wait",
  "choices": [
    { "id": "ship", "percentage": 22 },
    { "id": "wait", "percentage": 78 }
  ],
  "percentageSource": "provider-distribution",
  "model": "typesafe-ai/jev",
  "provider": "gateway",
  "warnings": [],
  "profile": "default",
  "routing": { "mode": "default", "selectedProfile": "default" }
}

Results are returned as both MCP structuredContent and JSON text for client compatibility. Choice IDs must be unique. Supply 2–64 mutually exclusive choices. Context can be a string, JSON object, or JSON array, up to 100,000 serialized characters.

What the percentages mean

Source

Meaning

provider-distribution

The evaluation provider's choice probabilities multiplied by 100. No normalization or invented probabilities.

model-estimate

A language model's requested probability estimates, validated for coverage, range, and a sum of one. Not calibrated confidence.

unavailable

An evaluation model returned a choice without a distribution. Every percentage is null, with a warning.

Jev's separate confidence statistic is not a selected-choice probability and is not substituted for one. Rounded native distributions may sum to 99% or 101%; their values are preserved. Estimates are validated, not silently normalized. Tied estimates use input order as the tie-breaker.

Decision policies and profiles

systemPrompt configures the global decision policy. A named profile adds its policy to the global policy and can optionally use a different model or provider. With native evaluation models, the policy goes into the question's instructions; the experimental API has no separate system-message parameter. In language mode it is a system message.

See multiple-profiles.json for a complete Jev configuration:

{
  "systemPrompt": "Prefer reversible actions and respect the stated constraints.",
  "tools": "both",
  "router": { "minimumProbability": 0.7 },
  "profiles": [
    {
      "id": "reliability",
      "description": "Releases, operational risk, and service reliability.",
      "systemPrompt": "Favor reliability and safe rollback over speed."
    },
    {
      "id": "cost",
      "description": "Purchasing, sizing, and resource allocation.",
      "systemPrompt": "Minimize total cost while meeting the requirements."
    }
  ]
}

tools

Exposed tools

Behavior of decide

routed (default)

decide

Chooses a profile, then evaluates the decision.

separate

decide, decide-default, decide-<profile-id>

Uses the default policy. The calling agent chooses a specialized tool.

both

All of the above

Routes automatically; explicit tools bypass routing.

With no profiles, decide makes one model call. With profiles and routing enabled, it makes two: one to select a profile from its description, one to evaluate with that policy. Explicit tools always make one call. Profiles do not vote or blend scores.

This is a two-stage decision tree. A single router keeps latency bounded and makes policy selection observable. Recursive trees are not implemented. If profiles become numerous enough to need a hierarchy, that can be added as an explicit configuration structure.

router.model can override the default model. router.systemPrompt controls profile selection separately from the decision policies. router.minimumProbability is in [0, 1] and defaults to 0, meaning no threshold. A positive threshold falls back to default if the proposed profile's probability is too low or unavailable. Router errors fail the request; they do not silently switch policies. This threshold uses the router's stated probability source and is not a calibration guarantee.

The result reports the selected profile, proposed profile, routing percentage/source, model/provider, and whether a threshold fallback occurred. decide-default provides an explicit bypass when separate tools are enabled.

Providers

AI SDK packages and the lockfile are pinned because the experimental evaluation API may change in patch releases.

Provider kind

Default credential variable

Model modes

gateway

AI_GATEWAY_API_KEY (or supported Vercel OIDC)

evaluation, language, depending on the model

typesafe

TYPESAFE_AI_API_KEY

evaluation

openai

OPENAI_API_KEY

evaluation, language

anthropic

ANTHROPIC_API_KEY

evaluation, language

google

GOOGLE_GENERATIVE_AI_API_KEY

evaluation, language

openai-compatible

Set apiKeyEnv if required

language; requires baseURL

custom

Set apiKeyEnv or use the factory's defaults

Whatever the installed AI SDK provider supports

Provider names are configuration aliases: multiple entries may use the same provider kind with different endpoints or credentials. The providers object replaces the default provider map when supplied. All model references must point to a configured alias. Models default to mode: "evaluation"; set mode: "language" for general structured-output models when you need estimated percentages. The SDK's OpenAI/Anthropic/Google evaluation adapters return choices without distributions, so evaluation mode on those adapters reports percentages as unavailable.

Use the real model ID supported by your provider and account. A language model must support structured output compatible with Output.object. Provider-specific settings can be passed in model.providerOptions; they are not universally portable.

Direct Jev

jev-direct.json calls TypeSafe directly without Gateway. Its model ID is jev-latest, with the AI SDK provider's TYPESAFE_AI_API_KEY variable. This differs from the standalone TypeSafe SDK's credential name. You can use another environment variable by setting apiKeyEnv.

Language models

language-provider.json configures a direct OpenAI language model. The same pattern works for Anthropic and Google with their provider kinds and model IDs. A profile can override the global model:

{
  "id": "complex",
  "description": "Decisions involving several interacting technical tradeoffs.",
  "systemPrompt": "Consider long-term maintenance and opportunity cost.",
  "model": { "provider": "openai", "model": "gpt-5.6-luna", "mode": "language" }
}

Add the referenced provider to your top-level providers map. Routing can continue to use Jev while the selected profile uses another model.

Other AI SDK providers

Install the provider package locally. Set kind: "custom", module to its package name or local module path, and export to its provider factory. See custom-provider.json, a working factory configuration using the included OpenAI package. Pass factory settings through options; apiKeyEnv and baseURL override their corresponding settings when supplied.

The factory must return an AI SDK provider with languageModel(id) or evaluationModel(id). No packages are automatically downloaded at runtime. Local custom modules are trusted executable code, configured by the operator, never supplied through tool calls.

Runtime and verification

timeoutMs defaults to 30,000 and covers routing, retries, and evaluation together. maxRetries defaults to 2 for transient provider failures. Client cancellation propagates to provider requests. Invalid inputs fail before model calls. Provider failures and invalid model output return an MCP tool error with no recommendation; raw provider exception details are not returned because they may contain sensitive request data.

Each request is independent. There is no conversation memory, persistence, action execution, or cross-request policy mutation. Decision data is sent to the configured provider. Configured prompts guide model behavior; they are not a security boundary against prompt injection.

bun run lint
bun run prettier
bun run format:check
bun run typecheck
bun test
bun run test:e2e

Unit tests cover schemas, scoring semantics, routing thresholds, cancellation, and custom factories. E2E tests launch the built Node CLI through the actual MCP stdio client and use local HTTP provider fixtures with real AI SDK adapters. They cover native TypeSafe/Gateway transport, language estimates, tool discovery, routing, validation, timeout, malformed responses, and error redaction. A package test packs the release, installs it in a temporary directory using npm, and verifies its executable and MCP handshake without relying on workspace dependencies. That test needs npm registry access. These checks do not establish real model quality or live provider access; live calls require an operator-provided API key.

Release

Run the verification commands above, then npm publish --access public. The prepack hook builds the CLI before packing or publishing. Keep package.json, the CLI version, and the pinned installation example aligned when changing the version.

Licensed under the MIT license.

API references

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI assistants to access and execute automated decision services from IBM Decision Intelligence or IBM Automation Decision Services. It exposes deployed decision operations as tools for platforms like Claude Desktop and IBM watsonx Orchestrate.
    11 npm
    7
    Apache 2.0
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables agents to interrogate payment routing decisions through six tools: route transactions, explain decisions, simulate scenarios, inspect segment evidence, normalize decline codes, and review backtest summaries. It provides read-only access to the routing engine, allowing natural-language queries without modifying any decisions.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables coding agents to scout, rank, and preflight software work before implementation, returning evidence-backed ACT, VERIFY, or SKIP decisions for issues and pull requests.
    59 npm
    2
    MIT