Skip to main content
Glama
holeyfield33-art

Aletheia Token Guard (ATG)

Aletheia Token Guard (ATG)

CI Vibe Check Code Scanner License: MIT

Slim MCP server for token/usage awareness and durable work checkpoints.

Plugin-ready companion to Horos (context router + signed receipts) and Mneme (persistent memory).

Status: experimental v0.1 — single-user local sidecar. See SECURITY.md.


Why ATG?

Agents die mid-task when they hit rate limits, spend caps, or context budgets. ATG gives any MCP host a thin side-car that:

  1. Answers "can I keep going?" (rate-limit headers + simple policy)

  2. Lets the agent save a checkpoint and resume later

  3. Stays out of the way of context selection (Horos) and long-term memory (Mneme)

It is deliberately minimal. No multi-tenant auth, no dashboards, no full connector zoo in v0.


Related MCP server: snapshot-mcp-server

Tools (v0)

Tool

Purpose

check_usage

Rate-limit / budget signal. Returns proceed / budget_low / pause

save_checkpoint

Persist work progress under a work_id

load_checkpoint

Retrieve the latest checkpoint for a work_id

list_checkpoints

List incomplete / recent work (limit clamped 1–500)

mark_done

Mark a work item complete

Optional meta on checkpoints can hold a Horos receipt_hash or Mneme memory key.

check_usage — header path

Preferred: pass the raw provider response headers plus platform:

{
  "platform": "openai",
  "estimated_tokens": 5000,
  "headers": {
    "x-ratelimit-remaining-tokens": "42000",
    "x-ratelimit-remaining-requests": "8"
  }
}

ATG parses OpenAI / Anthropic header names (case-insensitive). You may also pass remaining_tokens / remaining_requests directly if the host already extracted them.

Pass the real platform name when you pass headers. platform has no default — if you omit it (or pass something ATG doesn't recognize), ATG merges both the OpenAI and Anthropic parsers rather than guessing OpenAI, so real Anthropic headers are never silently misread as "no limit data" and turned into a false proceed.

ATG does not intercept provider traffic. The host/agent must supply headers or remaining counts. Policy is advisory.

Policy:

  • pause — remaining tokens ≤ 0, remaining < estimate, or requests ≤ 1

  • budget_low — remaining < 1000, or remaining < estimate / low_threshold (default 0.2)

  • proceed — otherwise, or when no limit data is supplied


Quick start

git clone https://github.com/holeyfield33-art/ATG.git
cd ATG
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

# stdio (recommended for MCP hosts)
python -m atg

# streamable-HTTP is UNAUTHENTICATED — local-only
# requires explicit opt-in; binds to 127.0.0.1 by default:
python -m atg --transport streamable-http --port 8765 --allow-remote-http

# to actually expose it beyond this machine, pass --host explicitly too
# (still requires --allow-remote-http):
python -m atg --transport streamable-http --port 8765 --host 0.0.0.0 --allow-remote-http

Security: streamable-HTTP

streamable-HTTP has no authentication. It is intended for local development only. The server refuses to start HTTP mode unless you pass --allow-remote-http or set ATG_ALLOW_REMOTE_HTTP=1. Prefer stdio for real hosts.

Full notes: SECURITY.md.


Configuration

Env

Meaning

ATG_DB_PATH

SQLite path (default ~/.atg/checkpoints.db)

ATG_INTEGRITY_KEY

Optional HMAC-SHA256 key (covers work_id, platform, status, data, meta, token_snapshot, created_at)

ATG_ALLOW_REMOTE_HTTP

Set to 1 to allow unauthenticated HTTP transport

JSON fields (data, meta, token_snapshot) are capped at ~512 KB. Store large blobs externally and pass a URI.

work_id max 256 chars; charset [A-Za-z0-9._:/-].

SQLite uses WAL + busy_timeout=5000 for lock contention, and _connect() separately retries (up to 3 attempts, exponential backoff starting at 50ms) on a sqlite3.OperationalError raised before a connection is established — e.g. transient contention creating the db file/directory on cold start. Old versions per work_id are pruned (keep last 20).


Example agent loop

See examples/agent_loop.py: extract headers → check_usage policy → checkpoint on pause → resume.

python examples/agent_loop.py

Local development & testing (Codespaces)

Everything below runs the same way in a GitHub Codespace as it does anywhere else — no extra setup beyond what's already in this repo.

1. Get the code and a clean environment

git clone https://github.com/holeyfield33-art/ATG.git
cd ATG
python -m venv .venv
source .venv/bin/activate        # every new terminal/session needs this re-run
pip install -e ".[dev]"

pip install -e . is an "editable" install — it links the package to this checkout instead of copying it, so edits to atg/*.py take effect immediately without reinstalling.

2. Run the automated test suite

pytest -q

Expect every test to pass, with no failures or errors (46 passed as of this writing — the exact count will drift as tests are added). -q just means quiet output (dots instead of a line per test); drop it (pytest) if you want to see each test name as it runs.

To run one file or one test while you're iterating:

pytest tests/test_checkpoint.py -v          # one file, verbose
pytest tests/test_checkpoint.py -k tamper   # only tests with "tamper" in the name

3. Run the server by hand (stdio)

python -m atg

This starts the MCP server on stdio and blocks, waiting for an MCP client to talk to it over stdin/stdout — it won't print anything on its own. Ctrl+C to stop. This is how a real MCP host (Claude Desktop, an agent framework, etc.) would run it; there's nothing to click or browse to.

4. Run the worked example

python examples/agent_loop.py

This exercises the whole flow in-process — no MCP host needed — so it's the fastest way to see check_usagesave_checkpointload_checkpoint actually working end to end. Read examples/agent_loop.py alongside the output; it's short and it's the clearest map of how the pieces fit together.

5. Verify the security fixes yourself

If you want to see the properties SECURITY.md claims actually hold — rather than take the docs' word for it — drop this into a scratch file and run it. It tries the exact three attacks that were open before this round of fixes and confirms each is now blocked:

# scratch_verify.py — safe to delete after running
import sqlite3, tempfile
from pathlib import Path
from atg.checkpoint import CheckpointStore

with tempfile.TemporaryDirectory() as td:
    db = Path(td) / "verify.db"
    s = CheckpointStore(db_path=db, integrity_key="test-key")
    s.save("job1", {"step": 1}, meta={"receipt_hash": "abc123"},
           token_snapshot={"remaining_tokens": 90000})

    # 1. Tamper with meta/token_snapshot directly in the DB file, bypassing the API
    conn = sqlite3.connect(db)
    conn.execute("UPDATE checkpoints SET meta = ? WHERE work_id = ?",
                 ('{"receipt_hash": "FORGED"}', "job1"))
    conn.execute("UPDATE checkpoints SET token_snapshot = ? WHERE work_id = ?",
                 ('{"remaining_tokens": 1}', "job1"))
    conn.commit()
    conn.close()
    print("tamper detected:", s.load("job1")["integrity_ok"] is False)  # expect True

    # 2. Oversized / malformed work_id
    try:
        s.save("x" * 5000, {"a": 1})
        print("work_id validation: FAILED (accepted bad input)")
    except ValueError:
        print("work_id validation: OK (rejected)")

    # 3. Non-JSON-serializable data
    class Weird:
        pass
    try:
        s.save("w2", {"bad": Weird()})
        print("serialization check: FAILED (silently accepted)")
    except ValueError:
        print("serialization check: OK (rejected)")
python scratch_verify.py

All three lines should say the guarantee held. If any of them don't, that's a regression worth opening an issue over before it ships.

6. Sanity-check a fresh dependency install

Because mcp[cli] is a range (>=1.0.0,<3.0.0), not a single pinned version, it's worth occasionally confirming what actually gets installed matches what's tested:

pip show mcp | grep Version   # should currently print 2.1.1

If this ever prints something outside the tested range, don't trust the security posture claims until the test suite has been re-run against that version.


Design principles

  • Side-car, not platform. Compose with Horos and Mneme via MCP.

  • Headers first. Prefer live rate-limit headers over Admin APIs.

  • SQLite by default. Zero ops for personal / consulting use.

  • Loose integration seams. Checkpoint meta can reference Horos / Mneme IDs.

  • Honest limits. Single-user, local, no encryption at rest, advisory policy only.


License

MIT


Part of the Aletheia family — tools that make AI systems inspectable and trustworthy.

Available Tools

5 tools
check_usageA

Pre-work / mid-work usage check.

Preferred path: pass the raw provider response headers dict and the platform name; ATG will parse rate-limit fields. Alternatively pass remaining_tokens / remaining_requests explicitly (host-extracted).

platform should name the actual provider ("openai" or "anthropic") when headers is supplied — an omitted/unrecognized platform merges both parsers instead of guessing OpenAI, so real Anthropic headers are never silently misread as "no limit data" (which would report a false proceed on an exhausted budget).

If neither headers nor remaining_* are provided, returns a neutral proceed signal so agents do not block.

ParametersJSON Schema
NameRequiredDescriptionDefault
headersNo
platformNo
low_thresholdNo
estimated_tokensNo
remaining_tokensNo
remaining_requestsNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

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

No annotations are provided, so the description carries the behavioral burden. It discloses that ATG parses rate-limit fields, that an omitted/unrecognized platform merges parsers to avoid false proceeds, and that a no-input call returns a neutral proceed signal. It doesn't detail output shape, but an output schema exists.

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?

Three tight paragraphs with the purpose front-loaded. Every sentence adds either usage guidance or behavioral context, and the platform warning is detailed without being bloated.

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?

For a six-parameter optional tool with no schema descriptions, two parameters are undocumented in the description. The core call path is clear and the output schema covers return values, so the tool is usable but not fully complete.

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?

Schema description coverage is 0%, so the description must supply parameter meaning. It explains headers, platform, remaining_tokens, and remaining_requests well, but it never mentions low_threshold or estimated_tokens, leaving two parameters semantically underdetermined.

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 opens with 'Pre-work / mid-work usage check', naming the exact operation and timing. It clarifies the tool consumes provider headers or remaining counts to determine whether to proceed, which cleanly separates it from sibling checkpoint and done tools.

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

Usage Guidelines5/5

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

It gives an explicit preferred path ('pass the raw provider response headers dict and platform name') and an alternative via remaining_tokens/remaining_requests. It also warns when platform must be set, what happens if omitted, and that empty input returns a neutral proceed signal, so an agent knows when and how to call it.

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

list_checkpointsB

List incomplete work items (limit clamped to 1–500).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
platformNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3.3/5.0
Behavior3/5

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

The description adds useful behavioral detail by disclosing that limit is clamped to 1–500. With no annotations provided, the description carries the disclosure burden, but it does not mention ordering, pagination, default behavior beyond the schema, or whether the operation is purely read-only, though 'List' strongly implies that.

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 a single efficient sentence with no filler. The core purpose is front-loaded, and the critical clamping detail is provided in a compact parenthetical that 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?

For a simple two-parameter list tool, the description is mostly adequate, and the presence of an output schema reduces the need to describe return values. The main gap is the undocumented platform parameter, which could cause an agent to misuse filtering or miss an important behavioral nuance.

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?

The description adds meaning for the limit parameter by stating the clamping range, which is genuinely useful beyond the raw schema. However, the platform parameter is entirely unexplained, and schema description coverage is 0%, so an agent is left guessing what values platform accepts, what null means, and how filtering behaves.

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 uses a specific verb ('List') and a clear resource ('incomplete work items'), so an agent knows the core action and scope. It doesn't explicitly differentiate from siblings, but the sibling names are self-explanatory enough that listing is clearly distinct from saving, loading, marking done, or checking usage.

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 description implies this tool is for viewing incomplete work items, which gives some usage context. However, it does not explicitly state when to use this instead of load_checkpoint, mark_done, or save_checkpoint, nor does it mention any exclusions or prerequisites.

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

load_checkpointB

Load the latest in-progress checkpoint for work_id.

ParametersJSON Schema
NameRequiredDescriptionDefault
work_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3.4/5.0
Behavior2/5

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

With no annotations, the description must carry the full behavioral burden. It explains what is loaded but does not disclose side effects, what happens when no checkpoint exists, whether loading is read-only or restores state, or any requirements such as prior save_checkpoint usage.

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 a single concise sentence with no filler or redundant detail. It front-loads the core operation and scoping parameter effectively.

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 tool is simple, has one parameter, and an output schema is present, so return values do not need explanation. Still, the description omits important behavioral context such as error handling, side effects, and the relationship between loading and saving checkpoints, making it only minimally 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%, so the description must compensate. It only mentions work_id as the scope for loading, adding little beyond the schema's existing 'Work Id' title; it does not clarify format, origin, or relationship to other tools.

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 verb ('load') and a specific resource ('latest in-progress checkpoint') scoped by 'work_id'. This clearly distinguishes it from sibling tools like save_checkpoint, list_checkpoints, and mark_done.

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 description implies usage: use this tool when you need the latest in-progress checkpoint for a work_id. However, it does not explicitly explain when to prefer list_checkpoints or save_checkpoint, nor does it state any exclusions.

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

mark_doneA

Mark all in-progress checkpoints for work_id as done.

ParametersJSON Schema
NameRequiredDescriptionDefault
work_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.7/5.0
Behavior3/5

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

With no annotations, the description carries the full behavioral disclosure burden. It clearly states that all in-progress checkpoints are affected and that they become 'done', but it does not mention whether the action is reversible, whether permissions are required, or what happens if there are no in-progress checkpoints.

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 a single sentence with no filler. The action, scope, and target are all front-loaded and every word earns its place.

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

Completeness4/5

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

Given the low complexity of one required parameter and the presence of an output schema, the description covers the essential call information. Missing details like no-op behavior or reversibility are minor for this simple bulk state-change tool.

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%, so the description must compensate. It only repeats the parameter name 'work_id' without explaining what a work_id represents, how to obtain it, or any format constraints. The meaning is largely inferred from the tool's purpose.

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, 'Mark', and names the exact resource: 'all in-progress checkpoints for work_id'. It clearly distinguishes this tool from siblings like list_checkpoints and load_checkpoint by stating the state transition it performs.

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 intended use is implied: call this when in-progress checkpoints should be marked done. However, it does not explicitly state when not to use it or how it compares to sibling tools like save_checkpoint or check_usage.

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

save_checkpointA

Save a durable checkpoint for work_id.

meta is a free-form bag — useful for Horos receipt_hash or Mneme memory keys. JSON fields are capped (~512 KB); store large blobs externally.

ParametersJSON Schema
NameRequiredDescriptionDefault
dataYes
metaNo
work_idYes
platformNo
token_snapshotNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A3.9/5.0
Behavior4/5

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

With no annotations, the description carries the full burden and adds meaningful behavioral context: 'durable' implies persistence, and the size cap ('~512 KB') plus 'store large blobs externally' disclose important limitations. It does not cover overwrite semantics or side effects, but the provided constraints are valuable.

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 compact and front-loaded: one sentence states purpose, followed by two short, high-value sentences about meta and size constraints. Every sentence earns its place with no redundant or filler content.

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?

Required parameters is work_id and data, both understandable from the description and schema. But optional parameters platform and token_snapshot are not contextualized, and behavior around overwriting or updating an existing checkpoint for the same work_id is absent. The output schema exists, so return-value details are not needed, but the gaps around optional params and lifecycle behavior make this only partially complete.

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?

Schema description coverage is 0%, so the description must compensate. It explains meta as a free-form bag for Horos receipt_hash or Mneme memory keys and notes JSON size limits. However, platform and token_snapshot are left unexplained, and data is only implicitly described via 'checkpoint' and the size cap.

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 opens with 'Save a durable checkpoint for work_id,' which names a specific verb, resource, and target. It clearly differentiates from siblings like load_checkpoint, list_checkpoints, and mark_done by indicating this is the write/save operation.

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 description states what the tool does but does not explicitly say when to use it versus alternatives. There is no mention of when to call save_checkpoint instead of mark_done or check_usage; usage is only implied by the verb 'save' and the checkpoint resource.

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. 5 tool updatesv0.1.0
    • First observedcheck_usage
    • First observedlist_checkpoints
    • First observedload_checkpoint
    • First observedmark_done
    • First observedsave_checkpoint

TDQS

A3.9/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a clear, singular responsibility: usage checking, checkpoint persistence, resume, listing, and completion. Even the related save/load/list checkpoint tools are easy to distinguish by their action and return value.

Naming Consistency5/5

All tool names follow a consistent snake_case verb_noun convention: check_usage, save_checkpoint, load_checkpoint, list_checkpoints, mark_done. The pattern makes behavior predictable and easy to infer.

Tool Count5/5

Five tools is well-scoped for a focused guard/checkpoint server. Each tool addresses a distinct step in the pre-work, mid-work, resume, and completion lifecycle without unnecessary overlap.

Completeness4/5

The core workflow is covered: usage check, checkpoint save/load, incomplete work listing, and completion marking. A minor gap is the lack of an explicit checkpoint delete/abort operation for abandoned work, but this does not create a dead end for the primary use case.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers