Skip to main content
Glama
sberan

eink-mcp

by sberan

eink-mcp

An MCP server that hosts files for e-ink devices and syncs them down.

Agents put files here with MCP tools. Each file version lands once at an immutable, content-addressed public URL in a Vercel Blob store, and a small manifest.json maps paths to those URLs with their sha256. Only the manifest is ever overwritten, so a reader can never see a manifest that disagrees with the file it names; it can only be up to a minute behind. A device such as a jailbroken Kindle running eink-ui points its update URL at that manifest and pulls whatever changed on every start, wake and reload. Nothing has to reach the device: it is behind NAT and asleep most of the day, so it always pulls.

agent ──MCP──▶ eink-mcp ──put──▶ Vercel Blob (public URLs + manifest.json) ◀──pull── device

Tools

tool

effect

status

the public base URL to set as the device's update URL, the manifest URL, file count

list_files

every file with size, sha256, URL and last update

put_file

upload content (text) or content_base64 (binary) at a relative path

put_file_from_url

download a URL into the store, for large builds coming out of CI

get_file

read a file back (text or base64, truncated past 512 KiB)

delete_file

remove a file; devices drop their copy on the next sync

Paths are relative and map straight onto the device's app directory. On eink-ui devices app.js is the React bundle and eink-host is the host binary; changing either restarts the host.

Related MCP server: slm-mesh

Run it

Environment:

  • BLOB_READ_WRITE_TOKEN (required): a Vercel Blob read-write token. This is the only credential; the store is the only state.

  • EINK_PREFIX (default eink/): the folder inside the store, one per device or fleet.

npx eink-mcp                      # from npm, stdio
nix run github:sberan/eink-mcp    # from the flake, stdio

Claude Code

claude mcp add eink -e BLOB_READ_WRITE_TOKEN=... -- npx eink-mcp

pg_mcp (Nix runtime)

pg_mcp builds the flake at a pinned commit and runs it over stdio; the Blob token is supplied as the server's bearer credential through token_env.

SELECT mcp.register_server('eink', auth => 'bearer',
  options => '{"token_env":"BLOB_READ_WRITE_TOKEN","env":{"EINK_PREFIX":"kindle/"}}'::jsonb,
  runtime => '{"kind":"nix","source":"github:sberan/eink-mcp","revision":"<commit>",
               "attribute":"mcp","executable":"bin/eink-mcp"}'::jsonb);
-- then set the bearer token (the Blob token) and wait for mcp.status('eink').runtime = ready

Manifest

{ "version": 1, "generated": "2026-09-17T01:59:51Z",
  "base": "https://<store>.public.blob.vercel-storage.com/kindle/",
  "files": { "app.js": { "sha256": "…", "size": 123304, "url": "…", "content_type": "application/javascript", "updated": "…" } } }

A device keeps the manifest's ETag and the sha256 of each file it holds, downloads only files whose hash changed, verifies the hash (the CDN can lag a file behind its manifest for up to a minute, in which case the device simply tries again on its next sync), and deletes files that left the manifest.

Develop

npm install && npm run build
BLOB_READ_WRITE_TOKEN=... npm run smoke   # end to end against a throwaway prefix

Available Tools

6 tools
delete_fileDelete a fileA

Remove a file from the store and the manifest. Devices delete their copy on the next sync.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

TDQS

A3.8/5.0
Behavior4/5

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

With no annotations, the description carries the burden. It discloses an important side effect: 'Devices delete their copy on the next sync,' which is crucial for understanding the tool's behavior beyond just removing the file. It also indicates the deletion affects both the store and the manifest, adding completeness. This provides significant behavioral context that is not available elsewhere.

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 two short sentences, achieving high clarity with minimal words. The first sentence states the action, and the second adds an important side-effect. It is front-loaded and efficient, with no superfluous information.

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 low-complexity tool (one param, no output schema), the description is quite complete. It tells the agent what happens to the file and the manifest, and mentions sync behavior. The only minor gap is the lack of explicit path format, but that is not critical for most use cases. Overall, it's sufficient for an agent to call the tool correctly without additional context.

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 one parameter 'path' with no description, and schema coverage is 0%. The tool description says 'Remove a file from the store' but does not explain what 'path' means (e.g., absolute path, relative path, or naming convention). The agent must infer the path semantics. Since there is only one param and the description gives some context, it's acceptable but leaves ambiguity.

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 clearly states the action ('Remove a file from the store and the manifest') with a specific resource ('file'). It distinguishes from siblings like 'put_file' and 'get_file' by focusing on deletion. However, it could be more explicit about the file being referred to (e.g., by path).

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 when to use this tool (when a file needs to be removed) but does not provide explicit guidelines for when not to use it or mention alternatives. For instance, it doesn't mention that 'put_file' might be used to overwrite rather than delete, or if there is a separate batch delete. It's adequate but not explicit.

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

get_fileGet a fileA

Read a file back: text for text types, base64 otherwise. Large files are truncated; use the URL from list_files for the whole thing.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYes

TDQS

A4.1/5.0
Behavior4/5

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

With no annotations provided, the description carries most of the burden and does well by disclosing two key behaviors: text/base64 return format and truncation for large files. It could add error behavior, but for a single-parameter read tool this is solid coverage.

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 sentences, no filler, with the essential encoding behavior and truncation caveat front-loaded. Every clause 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?

For a simple one-parameter read tool with no output schema, the description covers the main behaviors an agent needs: encoding, truncation, and pointer to the alternative. It does not discuss error cases, but the tool's complexity is low and the description is largely complete on its own.

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 schema has 0% description coverage for the path parameter, so the description must compensate, but it adds no detail about path format, relative vs. absolute paths, or file resolution. The meaning of 'path' is inferable from the parameter name, but the description itself contributes nothing to parameter semantics.

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 verb 'Read a file back,' identifies the resource, and explains the return encoding (text for text types, base64 otherwise). It also distinguishes itself from siblings by flagging truncation and pointing to list_files for the full file.

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 clear context for when to use this tool, including the important large-file limitation and the explicit alternative: 'use the URL from list_files for the whole thing.' It does not enumerate exclusions, but the guidance is actionable and sufficient for a simple read operation.

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

list_filesList filesA

Every file in the store with its size, sha256, public URL and last update.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4/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 burden. It discloses the output fields and implies a read-only bulk operation, but it does not mention pagination, potential large payloads, or any authentication requirements. For a listing tool this is a moderate gap, but the core behavior is clear.

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?

A single, front-loaded sentence that states the scope ('Every file') and the relevant fields. No fluff or unnecessary detail.

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 parameterless listing tool without an output schema, the description adequately conveys the return content and scope. It does not mention ordering or limits, but these are minor for a simple inventory operation. The tool is sufficiently complete for an agent to call it correctly.

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?

There are zero parameters, so the description does not need to explain them. The baseline for 0 params is 4, and the description correctly adds no redundant parameter information.

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 verb 'list' and resource 'files', and specifies the exact fields returned (size, sha256, public URL, last update). This distinguishes it from siblings like get_file (single file) and put_file (upload) without ambiguity.

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 is the tool for obtaining a complete inventory of files, but it does not explicitly mention when to use it over get_file for a single file or delete_file for removal. The context is clear, but no explicit alternatives or exclusions are given.

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

put_filePut a fileA

Upload a file by path (relative, as it will appear in the device app directory). Give text as content or binary as content_base64. Devices pick it up on their next sync.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesrelative path, e.g. app.js or data/2026-09-16.json
contentNoUTF-8 text content
content_typeNoMIME type; guessed from the extension when omitted
content_base64Nobinary content, base64

TDQS

A3.8/5.0
Behavior3/5

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

With no annotations provided, the description carries the full burden. It discloses two meaningful behaviors: files appear in the device app directory and are delivered on the next sync (asynchronous delivery). It does not mention overwrite behavior, idempotency, failure cases, or any authentication prerequisites, which would strengthen transparency for an upload operation.

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 sentences, zero filler. The primary action and path semantics are front-loaded, and the content-mode and sync-timing details follow in a logical, compact order. Every sentence 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?

For a fairly simple upload tool with four well-documented parameters and no output schema, the description is nearly sufficient. It covers path meaning, content encoding choices, and delivery timing. The only gap is what happens on conflict or failure (e.g., whether existing files are overwritten), which would make it 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 100%, so the baseline is 3. The description reinforces the schema by saying 'text as content or binary as content_base64' and clarifies that path is relative to the app directory, but it adds little beyond what the schema already documents for each parameter.

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 a specific verb and object ('Upload a file') and immediately clarifies the path semantics as 'relative, as it will appear in the device app directory.' This distinguishes it from siblings like get_file, delete_file, and put_file_from_url, which are separate operations or input channels.

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 provides practical context: when you have local text or binary content Encoder, you pass content or content_base64, and the file is picked up on next sync. However, it does not explicitly name alternatives (e.g., put_file_from_url) or state when not to use this tool, leaving some selection inference to the agent.

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

put_file_from_urlPut a file from a URLA

Download a URL and store it under path, so large binaries (a host build from CI, for example) never pass through the conversation.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYes
pathYes
content_typeNo

TDQS

A4/5.0
Behavior3/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It honestly describes the write action and adds a helpful side-effect detail (content bypasses the conversation), but it does not disclose overwrite semantics, access requirements, or error behavior. This is modest disclosure rather than full transparency.

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?

A single 24-word sentence that leads with the action, states the storage target, and closes with the motivating case. Every phrase contributes to understanding and no redundancy is present.

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 three-parameter tool with no output schema, the description is mostly sufficient: it identifies the source, destination, and intended use case. However, with no annotations and no schema descriptions, the omission of `content_type` and any note about overwriting an existing file leaves some ambiguity for the agent.

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 clarifies that `url` is the download source and `path` is the storage destination, but it never explains `content_type`, which appears only as an unannotated schema property. This partial compensation leaves one parameter semantically under-specified.

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 a clear verb ('Download') and resource ('a URL') and specifies the outcome ('store it under `path`'), which makes the tool's function unambiguous. It also implicitly distinguishes itself from the sibling `put_file` by explaining that content never passes through the conversation, so an agent can tell them apart.

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 phrase 'so large binaries (a host build from CI, for example) never pass through the conversation' gives a concrete scenario and rationale for choosing this tool. It does not explicitly name `put_file` as the alternative or state when not to use it, stopping short of full when/when-not guidance.

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

statusStore statusC

The public base URL devices sync from (set it as update_url on the device), the manifest, and the file count.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

C2.8/5.0
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It does not state whether this is a read-only operation, whether it requires authentication, what the response format looks like, or whether the file count is computed live or cached. The description is a noun phrase, not a statement of behavior.

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

Conciseness4/5

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

The description is a single concise sentence that front-loads the key information. It is not verbose, but it could be improved by adding a verb and a clearer statement of purpose.

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?

For a zero-parameter tool with no output schema and no annotations, the description should clarify what the agent can expect. It mentions the three pieces of data returned, but it does not explain the response structure, whether the manifest is a list of files, or how this relates to sibling tools. The description is too thin to fully support correct invocation and interpretation.

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, so there is no parameter semantics burden. The description adds context about what the tool returns (base URL, manifest, file count), which is useful given the empty schema. Baseline 4 is appropriate for a zero-parameter tool.

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

Purpose3/5

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

The description states the tool exposes the public base URL, manifest, and file count, which gives a specific resource and scope. However, it does not use a verb like 'get' or 'retrieve', and it does not clearly distinguish itself from sibling tools like list_files, which could also return file information.

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?

No guidance is given on when to use this tool versus list_files or other siblings. The description implies it is a status/overview endpoint, but it does not explicitly state when an agent should choose it over alternatives.

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. 6 tool updatesv0.1.0
    • First observeddelete_file
    • First observedget_file
    • First observedlist_files
    • First observedput_file
    • First observedput_file_from_url
    • First observedstatus

TDQS

A3.8/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a distinct operation: status reports server-level info, list_files enumerates metadata, put_file and put_file_from_url are clearly separated by input source, get_file retrieves content, and delete_file removes files. There is no meaningful overlap that would cause an agent to select the wrong tool.

Naming Consistency4/5

Most tools follow a consistent verb_noun pattern: list_files, put_file, get_file, delete_file, and put_file_from_url extends that pattern naturally. The single outlier is status, which is a noun rather than verb_noun, but it is a conventional command name and not confusing.

Tool Count5/5

Six tools is well-scoped for a file store sync server. Each tool covers a necessary operation without redundancy, and the count is neither too thin nor too heavy for the stated purpose.

Completeness5/5

The tool surface covers the full file lifecycle: create/update via put_file and put_file_from_url, read via get_file and list_files, delete via delete_file, plus status for device sync configuration. There are no obvious missing operations for the domain.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers