The doors and tools¶
Reference. The MCP surface an agent consumes — every door, its tools, the result envelope, and the refusal modes. This is the consumer projection of the engineering contract; where a schema detail is not repeated here, the tool's own MCP schema is authoritative.
Tatrman speaks MCP over Streamable HTTP. Each service mounts one door at POST /mcp; the
HTTP probes (/health, /ready, /status, /metrics) sit beside it and are operational surface,
not part of this contract. Everything your agent can observe is specified here or in the tool
schemas — nothing depends on a door's internals, so a second implementation is possible by
construction.
The five doors¶
| Door | What it answers | Tools |
|---|---|---|
meta-mcp |
The model — what is known | get_model, get_object, list_objects, list_queries, resolve_area, search |
query-mcp |
The governed query path | query, compile |
lex-matcher-mcp |
Fuzzy candidate matching over searchable fields | match |
grounding-mcp |
Deterministic grounding of universal spans | ground_time, ground_geo, ground_money |
resolver |
Deterministic entity resolution against model vocabulary | resolve.bind:v1 |
The two-call shape most agents follow: resolve and ground the user's words into model
vocabulary (search / match / resolve.bind:v1 / ground_*), then express the intent as a
query over the modeled entities (query). The model door tells you what exists; the query door is
the only path to data, and it is always governed.
The result envelope¶
Every governed tool returns its formatted text in content[0] and a structured result envelope
in structuredContent (always a JSON object, never a bare array):
{
"ok": true, "tool": "query",
"rowCount": 5, "columnCount": 4, "truncated": false,
"format": "json", "mediaType": "application/json; charset=utf-8",
"columns": [ { "name": "id", "type": "Int64", "nullable": true } ],
"messages": [ { "severity": "warning", "code": "partial_results_truncated", "text": "…" } ],
"pipelineWarnings": [
{ "code": "security_predicate_applied", "severity": "info",
"text": "…", "sourceService": "validator", "metadata": { "sourceStage": "security" } }
]
}
pipelineWarnings is always present — an empty array when nothing happened, otherwise the
trail of everything the platform did to keep the answer legal: a row-level filter injected, a
column masked, a cap applied, a type coerced. This is the provenance attachment the contract
guarantees. Surface it to your user; do not swallow it.
The tools¶
query-mcp¶
query— run a query through the governed path (translate → validate → dispatch → worker). Required:source(query text),source_language(sql|transdsl|dfdsl|rel_node). Optional:parameters(bound map; types inferred from JSON),session_id(sticky routing, only honoured when the worker advertisessupports_stateful_sessions),format(jsondefault |csv|tsv|markdown),row_limit(clamped to[1, 5000], default 500),hide_columns_matching(regex list),row_numbering(none|one_based). Output: the result envelope above.compile— the front of the pipeline only (parse → validate; nothing executes). Required:source,source_language,target_dialect(mssql|postgresql|mysql_mariadb). Optional:parameters,apply_security(defaulttrue;falseneeds an admin role or you getpermission_denied). Output: compiled SQL +parameterPlan([{name, type, bound, label?}]).
meta-mcp¶
get_model(packages[], include_search_hints?, include_roles?, include_drill_map?, locale?)— the heavy call: a ModelBundle (entities, relations, tables, views, pattern/named queries, roles, drill maps, package versions).get_object(id)— typed detail by qualified name (e.g.er.entity.artikl).list_objects(kind?, package?, binding?)— the objects in scope (drained pagination).list_queries(package?, parse_status?)— query descriptors with SQL template + parameters.resolve_area(area)— the package set a subject area spans.search(query, limit?)— top-N over names, localized labels, aliases and search keywords, with scores and snippets. This is usually your first call: it turns the user's words into qualified model ids.
lex-matcher-mcp¶
match(name, category?, algorithm?, limit?)— fuzzy candidates over model-declared searchable fields.algorithmcascadesLEVENSHTEIN|TATRMAN|JARO_WINKLER(precision first, recall fallback). Czech-aware diacritic handling is contract-observable — the conformance suite asserts it.
grounding-mcp¶
ground_time,ground_geo,ground_money— deterministic grounding of universal spans ("last quarter", a place name, "5 mil. Kč") into typed values. Deterministic by construction: the same span grounds to the same value.
resolver¶
resolve.bind:v1— deterministic entity resolution against the model's vocabulary. One tool, fresh call or clarification-resume (an opaqueresumeTokencarries an unfinished resolution). Its refusal discipline is the point: a below-threshold match becomes a clarifying question, never a fabricated binding. See The identity contract for who the resolution runs as.
Refusal modes¶
A well-behaved answer sometimes says no, and your agent must handle it rather than paper over it:
ok: falsewith anerror_code— the governed result was denied or malformed (a denied column, a permission failure, bad arguments). The envelope tells you which.- Clarification —
resolve.bind:v1returns options + aresumeTokeninstead of a binding when the user's words are ambiguous. Ask the user; resume with their choice. - Empty — a resolution with zero bindings: the platform found nothing confident and said so. This is a correct outcome, not a failure to retry.
The guiding rule the whole surface is built on: refuse over guess. An agent that fabricates an answer where the platform refused is a bug — and the conformance suite is how you prove yours does not.