Skip to main content
Glama

laya-mcp

laya-mcp is a persistent local Model Context Protocol server for bounded decisions powered by Laya-CoreML. It loads one Core ML model at process startup and keeps it resident for every MCP request.

Codex CLI ──────┐
Claude Code ────┼── MCP stdio ──> laya-mcp ──> Laya-CoreML ──> Core ML / ANE
Other clients ──┘

The core server contains no client-specific behavior. Client examples live under examples/, and client notes live under docs/.

Status

The current server provides:

  • one model load per server process through the MCP server lifespan;

  • a stable generic info, decide, batch_decide, and conservative filter tool surface;

  • public binary, choice, and ordered_score decision semantics;

  • structured confidence, probabilities, token usage, and inference latency;

  • explicit rejection before inference if an input would be truncated;

  • serialized access to the resident Core ML model;

  • JSON logs on stderr, leaving stdout exclusively for MCP stdio messages.

Milestones 2–4 add exact Laya 0.1 token accounting, deterministic reusable chunk planning, composition/throughput benchmarks, stable decision primitives, and the conservative context-reduction filter primitive. See docs/laya-capabilities.md and docs/token-efficiency.md, plus docs/filtering.md.

This is alpha software. Laya decisions are probabilistic signals, not authorization, safety, legal, medical, or financial judgments.

Related MCP server: apple-fm-mcp

Requirements

  • Apple Silicon Mac

  • macOS 15 or newer for the default ANE checkpoint

  • Python 3.12 or 3.13 (3.12 is the currently validated project environment)

The default aac6fef/laya-multilingual-coreml-ane checkpoint supports a maximum of 96 total tokens across the question, options, and context. Call info rather than hard-coding that limit if you configure another model.

Install

python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install -e '.[dev]'

On first startup, Laya-CoreML may download the configured Hugging Face model before loading it. Inference is local after the model is present. To require a cached model or local model directory, set LAYA_MCP_LOCAL_FILES_ONLY=true or set LAYA_MCP_MODEL to that directory.

Run the stdio server:

laya-mcp

Do not print application output to stdout when using stdio transport. Server logs are structured JSON on stderr.

Tools

info

Reports the laya-mcp and backend versions, configured model, initialization state, platform, Python version, Core ML compute units, known model limits, and process-local metrics. The initialization duration is for this process on this machine.

decide

Arguments:

  • context: the small bounded text to evaluate;

  • question: the decision instruction;

  • decision: optional object with kind (binary, choice, or ordered_score) and, for non-binary decisions, at least two options;

  • confidence_threshold: optional number from 0 through 1;

  • request_id: optional caller-defined correlation ID.

Example arguments:

{
  "context": "player_controller.gd contains movement, jumping, acceleration and player animation logic.",
  "question": "Is this file relevant to fixing a player movement bug?",
  "request_id": "decision-17",
  "confidence_threshold": 0.8
}

The result includes the normalized result, model confidence, threshold outcome, applicable probability distribution, model/backend identifiers, local token usage, and measured inference latency.

batch_decide

batch_decide accepts ordered items with unique IDs. Use either:

  • shared_context with item contexts omitted; or

  • an independent context on every item with shared_context omitted.

The default fail_fast policy validates every item before inference and fails the whole call if any item is invalid. partial returns an explicit error entry in the original position for every failed item. No item is silently omitted.

Compact responses are the default and omit probability maps and per-item latency. Set response_detail to detailed when those fields are needed. Backend/model identifiers and aggregate metrics appear once at the response envelope.

{
  "shared_context": "Choose components relevant to a movement regression.",
  "confidence_threshold": 0.75,
  "items": [
    {"id": "a", "question": "Is the player controller relevant?"},
    {"id": "b", "question": "Is the audio mixer relevant?"}
  ]
}

This is MCP/API batching, not concurrent or fused model inference. The default ANE backend evaluates each question independently while holding the same serialization lock used by decide.

The server does not read files: clients must provide bounded context.

filter

filter accepts a criterion and ordered {id, text} candidates. It returns only retained candidates by default, which keeps rejected classification records out of the primary agent's context. Candidates are excluded only when Laya returns a binary negative result with confidence at or above the rejection_threshold (the default is 0.9). Relevant, uncertain, oversized, and failed candidates are retained. Use response_detail: "detailed" for per-candidate diagnostics.

{
  "criterion": "Relevant to fixing player acceleration behavior",
  "rejection_threshold": 0.9,
  "candidates": [
    {"id": "movement", "text": "player controller handles acceleration"},
    {"id": "audio", "text": "audio mixer loads music"}
  ]
}

Filtering reports candidate reduction and serialized MCP payload sizes. Those are local MCP payload measurements, not Codex/Claude token savings. See docs/filtering.md for the conservative policy and benchmarks.

Configuration

Variable

Default

Meaning

LAYA_MCP_MODEL

aac6fef/laya-multilingual-coreml-ane

Hugging Face ID or local directory

LAYA_MCP_REVISION

unset

Optional model revision

LAYA_MCP_LOCAL_FILES_ONLY

false

Disable model downloads/lookups

LAYA_MCP_COMPUTE_UNITS

model default

all, cpu, cpu_gpu, or cpu_ne

LAYA_MCP_LOG_LEVEL

INFO

Structured stderr log level

The model is loaded before the MCP server accepts requests. Give clients a startup timeout comfortably above the model's measured initialization time on your machine. The original development machine measured about 30.35 seconds; that is a local observation, not a general performance claim.

Client setup

Development

python -m pytest

The real-model benchmark is opt-in and runs only on a compatible Apple Silicon machine:

python benchmarks/token_composition.py
python benchmarks/token_efficiency.py --output /tmp/laya-token-efficiency.json
python benchmarks/evaluate_milestone5.py --output evaluation/results/milestone5.json

Unit and MCP integration tests use fake backends and do not load model weights. A real smoke test should be run on a compatible Apple Silicon Mac before release. The Milestones 5–6 quality evaluations are intentionally advisory; see docs/evaluation.md before using filter for automatic context exclusion.

Design constraints

  • no cloud LLM fallback;

  • no autonomous action loop;

  • no filesystem mutation or command execution;

  • no implicit input truncation;

  • every decision remains bounded and independently token-validated;

  • backend and MCP transport remain separate so other local Laya backends can be added.

License

Apache-2.0. Laya-CoreML and model weights are separate dependencies with their own licenses, notices, and model cards.

Available Tools

4 tools
batch_decideA
Read-onlyIdempotent

Make ordered bounded decisions in one MCP request.

Supply shared_context and omit item contexts, or omit shared_context and give every item its own context. This is API batching, not parallel inference.

ParametersJSON Schema
NameRequiredDescriptionDefault
itemsYes
failure_policyNofail_fast
shared_contextNo
response_detailNocompact
confidence_thresholdNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
modelYes
backendYes
metricsYes
failure_policyYes
response_detailYes

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish read-only, idempotent, and non-destructive behavior, so the bar is lower. The description adds meaningful behavioral context by stating decisions are 'ordered' and that this is 'API batching, not parallel inference,' which is not captured by annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences, front-loads the main purpose, and contains no filler. The either/or context rule is concise and directly actionable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the core batching semantics and the key context-mode constraint, and an output schema exists to describe return values. However, for a 5-parameter tool with several enums, it leaves failure_policy and response_detail semantics implicit and does not differentiate from the `decide` sibling.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 0% schema description coverage, the description must compensate for parameter meaning. It usefully clarifies the shared_context vs. item-context relationship, but it does not explain failure_policy, response_detail, or confidence_threshold beyond their names and enum values.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action and resource: 'Make ordered bounded decisions in one MCP request.' It clearly conveys batch scope and distinguishes itself from parallel inference, though it does not explicitly contrast with the sibling `decide` tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit either/or usage rule: supply `shared_context` and omit item contexts, or omit `shared_context` and provide per-item contexts. It does not state when to prefer this over `decide` or `filter`, but the batching context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

decideA
Read-onlyIdempotent

Make one bounded decision using the resident local model.

Decision kinds are binary, choice, and ordered_score. The server only signals needs_escalation; the caller remains responsible for any escalation.

ParametersJSON Schema
NameRequiredDescriptionDefault
contextYes
decisionNo
questionYes
request_idNo
confidence_thresholdNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
modelYes
resultYes
backendYes
detailsNo
confidenceNo
request_idNo
input_tokensYes
decision_typeYes
output_tokensYes
needs_escalationYes
confidence_thresholdNo
inference_latency_msNo

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavioral context beyond annotations: the result is bounded, uses a local model, and the server only signals needs_escalation while the caller retains escalation responsibility.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three tight sentences with no filler. The core purpose is front-loaded, and the decision-kind and escalation notes each earn their place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With five parameters and zero schema-level property descriptions, the tool description should explain how the parameters interrelate, but it only covers decision kinds and escalation signaling. It does not mention how to provide context/question or what confidence_threshold controls, leaving a significant gap for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, yet the description does not explain required parameters like context and question or optional ones like confidence_threshold and request_id. It only elaborates on decision kinds, which is one small part of the decision parameter, leaving most parameter semantics to inference.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('Make one bounded decision'), identifies the resource ('resident local model'), and distinguishes itself from the sibling batch_decide by emphasizing 'one'. Listing the decision kinds further clarifies the exact scope of the tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'one bounded decision' phrasing implies single-use versus batch_decide, and 'resident local model' gives context, but there is no explicit when-to-use or when-not-to-use instruction. The escalation note describes caller responsibility but not how to choose among the sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

filterB
Read-onlyIdempotent

Conservatively retain relevant, uncertain, failed, and oversized candidates.

Only a sufficiently confident irrelevant result excludes a candidate. The default response returns selected candidate text and aggregate metrics; use detailed for per-candidate diagnostics.

ParametersJSON Schema
NameRequiredDescriptionDefault
criterionYes
candidatesYes
response_detailNocompact
rejection_thresholdNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
detailsNo
metricsYes
summaryYes
failuresYes
selectedYes
response_detailYes

TDQS

B3.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already supply read-only, idempotent, and non-destructive signals, so the description adds genuinely new behavioral context: the conservative exclusion policy and the option between compact and detailed responses. This is useful beyond what the annotations can express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense, front-loaded sentences with no filler. The first sentence states the core policy, the second clarifies both the exclusion rule and the response-mode option, and every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Annotations and an output schema offset the need to explain side effects and return values, and the description covers the core policy and response modes. The main gaps are the undefined `criterion` parameter and the lack of routing guidance against sibling tools, which makes the definition adequate but not fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description compensates only partially. It hints at `response_detail` with 'use `detailed`' and at `rejection_threshold` with 'sufficiently confident,' but it never explains `criterion`, the candidate contract, or how the numerical threshold maps to rejection. Parameter names and defaults must carry most of the semantic burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence names a concrete action and scope: conservatively retain relevant, uncertain, failed, and oversized candidates. The threshold sentence further sharpens the behavior—only a sufficiently confident irrelevant result excludes a candidate—which clearly distinguishes it from a plain 'decide' tool. However, it never explicitly names or contrasts the sibling tools, so it stops short of full differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit guidance on when to use `filter` versus `info`, `decide`, or `batch_decide`. The wording implies a conservative filtering use case, but it does not state prerequisites, exclusions, or conditions that would route an agent to this tool instead of a sibling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

infoA
Read-onlyIdempotent

Report server, resident backend, model, platform, limits, and metrics.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
modelYes
backendYes
metricsYes
versionYes
platformYes
capabilitiesYes
compute_unitsYes
python_versionYes
backend_versionYes
initialization_stateYes

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, fully covering the safety profile. The description adds a list of reported topics but does not disclose additional behavioral traits such as authentication requirements, rate limits, or potential side effects. Given the strong annotation coverage, the additional value is moderate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One sentence, front-loaded with the verb 'Report', and each listed item is essential. There is no filler, and the list of reportable content is compact yet descriptive.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple (no parameters) and has an output schema that will document return values. The description covers the main categories of information, which is sufficient for an agent to invoke it correctly. There is no missing context that would lead to misuse.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters and 100% schema coverage (empty properties). Per rubric, missing parameter documentation is excused when there are no parameters. The description correctly focuses on the output categories rather than parameter details.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'Report' and enumerates the resources (server, backend, model, platform, limits, metrics). This clearly differentiates it from sibling tools like decide, batch_decide, and filter, which focus on decision-making rather than environment information.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The purpose clearly implies usage when the agent needs environment or runtime information. However, there is no explicit guidance about when to use this tool versus alternatives, nor any exclusion criteria. The context is clear but left to inference.

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. 4 tool updatesv0.1.0
    • First observedbatch_decide
    • First observeddecide
    • First observedfilter
    • First observedinfo

TDQS

A3.9/5.0

Scored across 4 tools

Disambiguation4/5

decide and batch_decide are clearly the single-item and batch variants of the same operation, while filter is a distinct conservative retention workflow. An agent might briefly hesitate between filter and repeated decide calls for relevance tasks, but the descriptions make each tool's purpose specific enough to avoid serious ambiguity.

Naming Consistency4/5

Most names are short, lowercase, action-oriented commands: info, decide, filter. batch_decide is the main deviation because it introduces an underscore and a compound form, but the naming remains readable and the relationship to decide is obvious.

Tool Count5/5

Four tools is well-scoped for this server's purpose: server introspection, single decisions, batched decisions, and candidate filtering. Each tool covers a distinct core workflow without redundancy or unnecessary surface area.

Completeness5/5

The tool surface covers the full apparent workflow: checking server state and limits, making a single bounded decision, making batched decisions, and conservatively filtering candidates. Escalation is intentionally left to the caller, so there are no obvious dead ends or missing operations.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables running MCP tools against local MLX models on your Mac, with hardware-aware configuration, CLI streaming, and a dashboard for routing and monitoring.
    1,953 npm
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP server that enables local Apple on-device Foundation Model access via any MCP client, supporting text generation, structured output, and multi-turn chat on macOS.
    2
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables MCP hosts to query Jev's typed decision model—yes/no, choice, and score—with calibrated probabilities, while defaulting to an offline mock and disclosing all egress unless explicitly enabled.
    Apache 2.0