Skip to main content
Glama
theoddden

io.github.theoddden/stamp

Stamp

The concierge MCP for agentic workflows: the small, high-frequency tools agents reach for constantly -- NTP time and clock drift, UUIDs, diffs, safe arithmetic, and tamper-evident attestation -- behind one endpoint.

A single NTP query tells you where your clock is right now. Drift history tells you where it is going: a clock that is consistently 200 ms fast and accelerating is a different problem from one that is stable at 200 ms fast. get_time takes the measurement; every call appends to a local log; get_drift reads the log and reports the trend.

Hosted endpoint (no sign-in, public): https://stamp-mcp.terradev.cloud/mcp

PyPI: pip install stamp-mcp  |  License: Apache 2.0


Quick start

Remote (streamable HTTP — no install needed)

Add to your MCP client config:

{
  "mcpServers": {
    "stamp": {
      "url": "https://stamp-mcp.terradev.cloud/mcp"
    }
  }
}

Local (stdio)

pip install stamp-mcp

Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "stamp": {
      "command": "stamp-mcp"
    }
  }
}

Restart Claude Desktop, then ask it "what tools do you have?"get_time should appear. If it doesn't, check ~/Library/Logs/Claude/mcp*.log.


Related MCP server: chuk-mcp-time

Tools

  • get_time — one NTP query: UTC time, this clock's offset in ms, network delay, stratum. Appends the sample to the drift log. Optional: server (default time.cloudflare.com), timezone (IANA name for a local field, e.g. America/New_York).

  • get_drift — analyzes the drift log: sample count, timespan, current/mean/stddev offset, drift rate in ms/day (least-squares fit), first-half vs. second-half rates, and a verdict: stable, drifting, or accelerating. Optional: server to filter by NTP host.

  • generate_uuid — random UUIDv4s for records, sessions, and identifiers. Optional: count (1–1000, default 1).

  • diff — unified diff between text_a and text_b, with added/removed line counts and an identical flag. Optional: context (lines of context, default 3).

  • calculate — safe math evaluator: + - * / // % **, parentheses, functions (abs round min max sqrt floor ceil exp log log2 log10 pow sin cos tan), constants pi e tau inf. Parsed to an AST; only whitelisted nodes are evaluated — no eval(), no arbitrary code. Required: expression.

  • attest — wrap any JSON payload in a tamper-evident record: a UUID, an NTP-verified timestamp (falls back to local clock; time_source says which), and a sha256 over the canonical record. Required: payload. Optional: server.

  • verify — recompute an attested record's hash and compare. Returns valid plus a reason; any modified field — payload, timestamp, id — breaks it. Required: attested.


The drift log

Every get_time call appends one JSON line to ~/.stamp/drift.jsonl (override with STAMP_DRIFT_LOG). The file is capped at 10,000 samples. Call get_time periodically — a cron job, a heartbeat, or just asking Claude "check the clock" — and get_drift turns the accumulated offsets into a trend.


HTTP transport

stamp_mcp/http_server.py serves the same dispatch logic over async HTTP via aiohttp:

stamp-mcp-http                      # binds 127.0.0.1:8000
STAMP_PORT=9000 stamp-mcp-http      # custom port

Endpoint

Method

Description

/mcp

POST

JSON-RPC 2.0 — single or batch; notifications → 202

/mcp

GET

SSE channel for server-to-client notifications (keep-alive)

/

GET

Service identity: name, version, endpoint map

/health

GET

{"status":"ok"} for proxies and monitors

/.well-known/oauth-protected-resource

GET

RFC 9728 metadata — public, no auth servers

/.well-known/agent-card.json

GET

A2A agent card

TLS is terminated by a reverse proxy. The production layout is two containers on one AWS instance (docker-compose.yml):

  • stamp — aiohttp server built from Dockerfile, internal network only. Drift log persists in the stamp-data volume.

  • caddy — terminates HTTPS at stamp-mcp.terradev.cloud (automatic Let's Encrypt) and reverse-proxies to stamp:8000.

Concurrency is capped at 100 simultaneous POST /mcp requests via asyncio.Semaphore; /health and / are exempt.


Self-hosting

git clone https://github.com/theoddden/Stamp-MCP.git
cd Stamp-MCP
docker compose up -d --build

Caddy handles TLS automatically once your DNS A record points at the host. See deploy/Caddyfile and deploy/stamp-mcp.service (systemd, bare-metal alternative).

Deployment to AWS is automated via GitHub Actions (deploy.yml) using SSM Run Command — no inbound SSH needed.


Wire protocol

>>> {"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}
<<< {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05",...}}
>>> {"jsonrpc":"2.0","method":"notifications/initialized"}
>>> {"jsonrpc":"2.0","id":2,"method":"tools/list"}
<<< {"jsonrpc":"2.0","id":2,"result":{"tools":[...]}}
>>> {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_time","arguments":{}}}
<<< {"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"..."}]}}

License

Copyright 2024 theoddden. Licensed under the Apache License, Version 2.0.


DISCLAIMER: Stamp queries public NTP infrastructure (Cloudflare, stratum 3) and is suitable for general agentic workflows. It is not intended for use cases requiring certified atomic precision, legal timestamp authority, or regulated audit trails. Use in production systems is at the implementer's risk.

Available Tools

2 tools
get_driftAInspect

Analyze the drift log built by get_time: reports current offset, drift rate (ms/day), and whether the clock is stable, drifting, or accelerating.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoOnly analyze samples from this NTP server

TDQS

A3.8/5.0
Behavior2/5

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

No annotations are provided, so the description must carry the full burden. It indicates an analysis operation ('analyze') and lists output fields, but does not explicitly state whether the tool is read-only, whether it requires prior calls to get_time, or what happens if the log is empty or missing. This lack of behavioral disclosure for a tool with no annotations is a significant gap.

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 that front-loads the purpose and directly states the tool's outputs. There is no redundant or unnecessary information, and it is well-structured for quick comprehension.

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?

The description covers the tool's purpose and output fields (offset, drift rate, status), which is adequate for a simple tool with one optional parameter. It does not mention edge cases like empty logs or error conditions, but given the simplicity and the reference to get_time as the data source, it is reasonably 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?

The schema has full 100% coverage for the single optional parameter 'server' with a descriptive comment. The description does not add any extra meaning about the parameter beyond what the schema already states, so it meets the baseline of 3 for high schema coverage without adding further value.

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 clearly states the tool's function: analyzing the drift log produced by get_time, and explicitly lists the reported outputs (offset, drift rate, stability status). This is a specific verb+resource definition that distinguishes it from the sibling get_time by referencing it as the source of the log.

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?

The description provides clear context by mentioning that the drift log is 'built by get_time', implying this tool is used after get_time has been called. While it doesn't explicitly state exclusions or alternatives, the reference to the prerequisite makes the usage context understandable for the single sibling scenario.

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

get_timeAInspect

Query an NTP server for current UTC time and this clock's offset, and append the sample to the drift log. Call it periodically to build drift history.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoNTP server to querytime.cloudflare.com

TDQS

A4/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 it discloses an important behavioral trait: the call appends a sample to the drift log, which is a side effect beyond a simple read. It does not go into failure modes or output format, but it covers the main behavioral surprise.

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 concise sentences: the first states the operation and side effect, the second gives usage guidance. Every sentence earns its place, and there is no redundant wording.

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?

For a tool with one optional parameter and no output schema, the description covers what it does, what side effect it causes, and how often to call it. It does not explicitly connect to the sibling get_drift, but the core calling context is sufficiently 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 100% for the single parameter, so the schema already documents 'server' as the NTP server to query. The description adds almost no semantic value beyond the schema, making the baseline 3 appropriate.

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 is specific: 'Query an NTP server for current UTC time and this clock's offset, and append the sample to the drift log.' It names a clear action, resource, and side effect, and it implicitly contrasts with the sibling get_drift by describing a data-collection operation rather than a read operation, though it never explicitly names the sibling.

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?

The instruction 'Call it periodically to build drift history' gives clear context for when the tool should be used. However, it does not mention alternatives or explicitly say when not to use it compared to get_drift.

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. 2 tool updatesv0.3.0
    • First observedget_drift
    • First observedget_time

TDQS

A4.2/5.0

Scored across 2 tools

Disambiguation5/5

get_time is responsible for sampling a new NTP timestamp and appending it to the drift log, while get_drift is responsible for analyzing the accumulated log. Although both mention offset, their roles are clearly separated: one collects data, the other interprets it.

Naming Consistency5/5

Both tools follow a consistent get_<noun> naming pattern, making the tool surface predictable and easy to understand. There is no mixing of styles or vague verbs.

Tool Count3/5

With only two tools, the server is on the thin side, but the two tools cover the core sampling and analysis workflow of a narrow domain. The count is understandable but still feels minimal.

Completeness4/5

The server covers the essential workflow: sample time and analyze drift. Minor gaps exist, such as no way to inspect raw log entries or clear/reset the drift log, but these are not fatal for the stated purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides accurate time information from Network Time Protocol (NTP) servers with timezone support and security filtering. Features whitelist-based server approval, blocks unauthorized sources, and delivers structured time output with fallback mechanisms.
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Provides high-accuracy time information by querying multiple NTP servers for consensus time, and comprehensive timezone support using IANA tzdata for conversions, DST handling, and clock drift detection independent of system time.
    7
    3
    Apache 2.0
  • A
    license
    A
    quality
    D
    maintenance
    Provides accurate UTC time by aggregating and verifying data from multiple reliable sources like WorldClockAPI, Google, and GitHub. It enables users to retrieve time in various formats including ISO, Unix timestamps, and human-readable strings with automatic source fallback for reliability.
    1
    1
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Provides real-time time awareness to Hermes Agent by exposing date, time, and timezone tools through MCP, enabling on-demand temporal queries.
    1
    -