mcp-reliable-adapter
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., "@mcp-reliable-adapterSubmit a support ticket: "Payment failed" with idempotency key pay-001"
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.
MCP Reliable Adapter

A small, clean-room reference implementation of an MCP server that accepts support tickets even when a downstream SaaS is temporarily unavailable. It demonstrates a transactional outbox, semantic idempotency, bounded exponential retries, dead-letter handling, recovery after restart, and an inspectable audit trail—with only SQLite as infrastructure.
Portfolio scope: this is deliberately compact and uses a fictional SaaS. It illustrates the delivery boundary and its failure modes; it is not presented as a production-ready help desk.
Why this exists
An MCP tool call and a third-party API call cannot share a transaction. If the process stops at the wrong instant, a naive adapter can lose the request or create the same ticket twice. This project first commits the request and an outbox item atomically, then performs the external side effect. Every retry carries the original idempotency key.
sequenceDiagram
participant C as MCP client
participant A as Adapter
participant DB as SQLite
participant S as Support SaaS
C->>A: submit_support_ticket(..., idempotency_key)
A->>DB: BEGIN IMMEDIATE
A->>DB: INSERT ticket + outbox + audit
A->>DB: COMMIT
A-->>C: pending + ticket_id
A->>DB: claim due outbox item
A->>S: create_ticket(..., same key)
alt success
S-->>A: external_id
A->>DB: delivered + audit
else transient failure
A->>DB: retry_at + bounded backoff + audit
else retry budget exhausted
A->>DB: dead_letter + audit
endRelated MCP server: Support Ticket Triage MCP
Quickstart
Requires Python 3.12+.
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install -e '.[dev]'
pytest
python -m build
mcp-reliable-adapterThe final command starts the official MCP Python SDK's stdio transport. A client can configure
the command directly; set ADAPTER_DB_PATH when the database should live elsewhere:
{
"mcpServers": {
"reliable-support": {
"command": "/absolute/path/.venv/bin/mcp-reliable-adapter",
"env": {"ADAPTER_DB_PATH": "/absolute/path/adapter.db"}
}
}
}Tools
submit_support_ticket
Inputs: subject, description, and a caller-generated idempotency_key. It commits a ticket,
outbox item, and audit event in one local transaction and returns a stable ticket_id. Repeating
the same payload and key returns the original ticket. Reusing the key for a different payload
returns a conflict instead of silently conflating two requests.
get_delivery_status
Input: ticket_id. It advances due demo deliveries, then returns pending, delivered,
dead_letter, or not_found, plus delivery metadata when available.
Local demo without an MCP client
python - <<'PY'
from pathlib import Path
from tempfile import TemporaryDirectory
from mcp_reliable_adapter import FakeSupportSaaS, ReliableAdapter
with TemporaryDirectory() as directory:
adapter = ReliableAdapter(Path(directory) / "demo.db", FakeSupportSaaS(failures_before_success=1))
ticket = adapter.submit_support_ticket(
subject="Synthetic demo",
description="No real customer data.",
idempotency_key="demo-001",
)
adapter.process_due() # simulated outage; retry scheduled
print(adapter.get_delivery_status(ticket["ticket_id"]))
print(adapter.get_audit_trail(ticket["ticket_id"]))
PYGuarantees and failure semantics
Durable acceptance: the tool returns only after the ticket, outbox item, and first audit record commit together.
Same-key consistency: a key identifies one canonical request body; conflicting reuse fails.
At-least-once delivery attempts: claimed work is requeued on startup, so a crash does not strand it permanently.
Effectively-once downstream creation—conditional: duplicate network attempts produce one logical ticket only if the downstream system honors the forwarded idempotency key.
Bounded retrying: exponential delay is capped, the attempt budget is finite, and exhausted work is visible as
dead_letterrather than looping forever.Auditability: acceptance, duplicate submissions, retry decisions, successful delivery, and dead-letter transitions are written as insert-only events by the application. SQLite does not make the table tamper-evident; a process with direct database access can still alter it.
Limitations and production path
The bundled SaaS is an in-memory fake; replace it with an authenticated HTTP adapter, explicit timeouts, response classification, and safe credential injection.
The demo processes due work during a status call. A real deployment should run a supervised worker independently of MCP request traffic.
SQLite is appropriate for a single-host example. Multiple workers need stronger claiming/lease semantics; a production service would commonly use PostgreSQL
FOR UPDATE SKIP LOCKED.There is a small crash window after the SaaS accepts a request but before local success commits. The downstream idempotency contract is therefore essential.
Restart recovery immediately requeues every
processingitem. A multi-process deployment needs expiring leases so one live worker's claim is not stolen.The audit trail has no retention policy, tamper-evident signatures, or PII redaction layer.
Authentication, authorization, rate limiting, observability export, schema migrations, and operator-driven dead-letter replay are intentionally outside this compact example.
Tool inputs are intentionally small demo strings but are not size-limited. Do not expose this server to untrusted clients without authentication, authorization, input limits, and resource quotas.
Tests
The ten focused test scenarios cover:
identical idempotent submissions;
conflicting key reuse;
successful delivery and audit state;
scheduled exponential backoff;
retry exhaustion and dead-letter state;
persistence and recovery after process restart;
stale concurrent claims respecting attempt counts and retry deadlines;
invalid retry configuration;
rejection of SQLite's connection-local
:memory:mode;generated MCP input/output schema compatibility.
Español (resumen)
Este proyecto muestra cómo aceptar una solicitud MCP de forma durable antes de llamar a un SaaS inestable. La solicitud y el mensaje de salida se guardan juntos en SQLite; luego un worker intenta la entrega con la misma clave de idempotencia. Los fallos temporales generan reintentos con espera exponencial y límite, y los fallos agotados quedan visibles en una cola muerta. El historial registra cada transición. El alcance es educativo: para producción faltan autenticación, un worker separado, leases multiworker, observabilidad y políticas de datos.
See PROVENANCE.md for the clean-room statement and SECURITY.md for the demo's trust boundary. Licensed under MIT.
Available Tools
2 toolsget_delivery_statusA
Return the current durable delivery state for a submitted ticket.
| Name | Required | Description | Default |
|---|---|---|---|
| ticket_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | |
| status | No | |
| attempts | No | |
| ticket_id | No | |
| created_at | No | |
| last_error | No | |
| updated_at | No | |
| external_id | No | |
| next_attempt_at | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description must convey behavior on its own. 'Return' clearly indicates a read-only operation, which is helpful, but it does not disclose behavior around invalid ticket IDs, missing tickets, or delivery-state semantics. Still, it gives a basic and accurate behavioral profile.
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 a single, focused sentence with no filler or redundant restatement. It front-loads the action ('Return') and the target resource, which is ideal for a simple one-parameter tool.
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?
This is a low-complexity tool with one required parameter and an output schema available, so the description need not explain return structure. It covers the essential purpose and resource, with the only notable gap being explicit usage context relative to the sibling submission tool.
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%, so the description should compensate for the single parameter. It adds context that the ticket must already be submitted, which helps explain ticket_id's origin, but it does not specify format, where to obtain the ID, or any constraints beyond what the schema's type and required fields already state.
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 states a specific verb ('Return') and a specific resource ('durable delivery state for a submitted ticket'), making the tool's purpose clear. It is naturally distinguished from the sibling submit_support_ticket by being a read/status operation rather than a submission, though it does not explicitly name the sibling.
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?
The phrase 'for a submitted ticket' implies this tool should be used after a ticket has been submitted, and the sibling name suggests the alternative creation path. However, there is no explicit when-to-use or when-not-to-use guidance, and no alternative is named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
submit_support_ticketA
Durably accept a support ticket for asynchronous downstream delivery.
| Name | Required | Description | Default |
|---|---|---|---|
| subject | Yes | ||
| description | Yes | ||
| idempotency_key | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | |
| status | No | |
| attempts | No | |
| ticket_id | No | |
| created_at | No | |
| last_error | No | |
| updated_at | No | |
| external_id | No | |
| next_attempt_at | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the behavioral disclosure burden. It does reveal two significant traits: acceptance is durable and delivery is asynchronous, which tells the agent this is not a synchronous end-to-end call. However, it does not disclose idempotency behavior, failure semantics, or what the returned output represents, which are material for a tool that requires an idempotency_key.
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 a single sentence with no filler. Every phrase earns its place: the core action, the durability guarantee, and the asynchronous nature of delivery are all packed into one concise, front-loaded statement.
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?
Given three required parameters, no annotations, 0% schema parameter coverage, and a sibling tool for status retrieval, this description is too sparse. It does not explain how idempotency_key should be used, what the expected response is, or how get_delivery_status relates to the asynchronous workflow. An agent can infer the basic action but not the full invocation contract.
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 compensate: subject and description are self-explanatory, but idempotency_key's semantics, required format, and expected reuse behavior are entirely unexplained. The agent is left to guess the purpose of a required parameter that is central to correct invocation.
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 uses a specific verb ('accept') with a clear resource ('support ticket') and adds meaningful qualifiers: 'durably' and 'asynchronous downstream delivery.' This makes the tool's submission-focused role distinct from the sibling get_delivery_status, which is clearly about checking status.
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?
The description implies when to use the tool—when submitting a support ticket—and the asynchronous wording hints at a later status check, but it never explicitly references the sibling get_delivery_status or states when not to use this tool. The routing between submit and status-check is 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.
2 tool updates
v0.1.0- First observed
get_delivery_status - First observed
submit_support_ticket
TDQS
Scored across 2 tools
The two tools have clearly distinct purposes: one submits a support ticket, the other retrieves delivery status for a previously submitted ticket. There is no overlap or ambiguity between them.
Both tool names follow a consistent verb_noun pattern: submit_support_ticket and get_delivery_status. The naming style is uniform and predictable.
With only two tools, the server feels thin, but the tools form a natural pair for a reliable adapter focused on submission and status tracking. The count is borderline but not unreasonable for the narrow scope.
The core workflow of durably accepting a ticket and checking its delivery state is covered. A retry or cancellation operation could be useful, but the primary path has no dead ends.
Maintenance
Related MCP Connectors
Remote MCP for A2A failure replay MCP, structured receipts, audit logs, and reviewer-ready evidence.
Remote MCP server for managing Muninx tickets, messages, ticket search, and support analytics.
MCP server for Support & Service Management
MCP server for Modern Treasury — payment orders, transactions, counterparties and ledgers.
Related MCP Servers
- AlicenseAqualityFmaintenanceAn MCP-compliant server that enables AI assistants like Claude Desktop to access and analyze Intercom support tickets with full conversation history.48Apache 2.0
- FlicenseAqualityFmaintenanceA local MCP server for governed support-ticket triage that reads synthetic tickets and knowledge articles, prepares evidence-backed recommendations, and records local audit events.9-
- AlicenseNot gradedqualityBmaintenanceAn MCP server that provides AI agents with a persistent, agent-native email mailbox for sending, receiving, and managing emails through bounded-context retrieval, idempotent operations, and explicit acknowledgement.MIT
- FlicenseNot gradedqualityBmaintenanceA production-grade MCP server over Postgres, providing secure data operations with tenant isolation, exact-once mutations, loop-aware rate limiting, and a tamper-evident audit trail.-