random-mcp-server
This server provides randomly generated, seeded data pools (people, words, values, coordinates, and empty) through a set of MCP tools.
server_info: Retrieve server metadata including name, version, active seed, and configuration flags likeallow_regenerate.list_records(kind, count?): Fetch the seeded pool of records for a given kind (people,words,values,coords, orempty), with an optionalcountto return only the first N records.get_record(kind, id): Retrieve a single record by its 1-based integer ID. Records are stable within a running instance.count_records(kind): Return the total number of records available for a given kind without fetching them all.regenerate(seed?)(opt-in): If enabled viaALLOW_REGENERATE=1, reseed the entire record pool for all clients — with a specific seed for reproducibility or a random one for a fresh shuffle. Disabled by default to prevent unintended changes in multi-user environments.
Data is deterministic within a session; a fixed RANDOM_SEED environment variable ensures reproducibility across restarts. The server supports stdio or HTTP transport and is available as a Docker image.
Click on "Install 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., "@random-mcp-serverlist 3 random people"
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.
random-mcp-server
An MCP server that returns random JSON
things — people, words, values, coordinates, and an always-empty list. It is a
Python / FastMCP adaptation of the Node/Express
random-server REST API: each REST route family becomes an
MCP tool.
Built with Python, uv, FastMCP, and make.
How the REST API maps to MCP
The REST server seeds a fixed pool of records when it starts and serves them at
/v1/<kind>, /v1/<kind>/count, and /v1/<kind>/:id. This server does the
same, exposing the pool through a small set of tools parameterized by kind
(people, words, values, coords, empty):
REST route | MCP tool |
|
|
|
|
|
|
|
|
(restart to reseed) |
|
Records are seeded at start-up, so a given id is stable until you call
regenerate. Pass a fixed seed (tool arg or RANDOM_SEED) for reproducible
data.
The regenerate tool is disabled by default — see
The regenerate tool is opt-in.
Differences from random-server
No
x-api-keyauth. The REST server's optionalAPI_KEYguard on/v1routes is not ported — MCP transports handle authentication differently (add FastMCP auth if a networked deployment needs it). TheAPP_NAME, seeding, and per-kind count behavior are preserved.No Swagger UI. The
/api-docsexplorer has no MCP equivalent; tool schemas are discoverable through the MCP protocol itself (e.g.make dev).
Example records
// get_record(kind="people", id=1)
{ "type": "people", "prefix": "Mr.", "first": "Augustus", "last": "Gomez",
"age": 42, "birthday": "7/8/1959", "gender": "male", "zip": "74948-0928",
"ssnFour": "0791", "phone": "(509) 504-8066", "email": "zeti@tipe.cv" }
// get_record(kind="words", id=1) -> { "type": "words", "value": "cezuwdi" }
// get_record(kind="values", id=1) -> { "type": "values", "name": "dafe", "value": -415365907192.2176 }
// get_record(kind="coords", id=1) -> { "type": "coords", "latitude": 88.43647, "longitude": -93.31203 }Related MCP server: unique-id-generator
Determinism & idempotency of records
Each server process builds one pool of records per kind when it starts, then serves that pool for the life of the process. What stays stable and what changes follows from that:
Within a running instance, records are idempotent. For as long as the process is up,
get_record(kind, id)returns the same record, andlist_recordsreturns the same pool in the same order. Ask for person1today and it's identical on the next call — until the pool is rebuilt (below).A reboot/restart reshuffles — unless you pin a seed. With no
RANDOM_SEEDset, the factory picks a random seed at start-up, so restarting the server (or launching a fresh container) yields a different pool. SetRANDOM_SEEDto a fixed value and every restart rebuilds the same pool, so records survive reboots.A shared instance shows everyone the same records. The pool lives in the process's memory, so all clients connected to the same long-running instance (Option B / C) see the same records — no seed required for them to agree, because they're reading one shared pool. Two separate unseeded instances (or two people each running their own) will not match unless both pin the same
RANDOM_SEED.Client-launched stdio gets a fresh pool per session. When a client starts the server itself (local dev or Docker/stdio, Option A), each session is its own process with its own start-up seed. Unseeded, those sessions won't agree with each other; set
RANDOM_SEEDto make them line up.regeneraterebuilds the shared pool for everyone on that instance.regenerate(seed=N)is reproducible (same seed → same pool);regenerate()with no argument picks a new random seed. Either way it mutates the shared state, so on a multi-client instance it changes the records every other connected client sees too. Because of that it is disabled by default (see below).server_inforeports the activeseed. Capture that value and feed it back viaRANDOM_SEED(at start-up) orregenerate(seed=…)to reproduce a pool you liked later.
Scenario | Same records? |
Same instance, repeated calls, no restart | ✅ Yes |
Same long-running instance, different clients | ✅ Yes |
After a restart / new container, no | ❌ No (reshuffled) |
After a restart / new container, fixed | ✅ Yes |
Two separate unseeded instances | ❌ No |
Two instances, both pinned to the same | ✅ Yes |
After | ❌ No (reshuffled) |
After | ✅ Yes |
The two regenerate rows assume ALLOW_REGENERATE is set; otherwise the tool is
unavailable (opt-in) and only a restart rebuilds
the pool.
The regenerate tool is opt-in
Because regenerate reseeds the one shared pool the whole process serves,
on a multi-user instance a single caller can reshuffle the records out from
under everyone else — no isolation, last-writer-wins. To prevent that, the tool
is disabled by default: when ALLOW_REGENERATE is unset the tool is not
registered at all, so it doesn't appear in the tool list and can't be called
(server_info reports "allow_regenerate": false).
Enable it only where reseeding is safe:
ALLOW_REGENERATE=1 make run # single-user stdio
docker run --rm -p 8000:8000 -e ALLOW_REGENERATE=1 ghcr.io/mitchallen/random-mcp-server:latestGuidance by deployment shape:
Shared long-running instance (Option B / C) — leave it off. Pin
RANDOM_SEEDif you need a specific reproducible pool, and treat the data as read-only. This is why the Docker image (which defaults to shared HTTP) ships withregenerateoff.Per-session / single-user (client-launched stdio or local dev) — each client gets its own process, so reseeding only affects that caller. Safe to set
ALLOW_REGENERATE=1.
Quick start
Requires uv.
make install # create .venv and sync deps
make test # run the test suite
make run # run the server over stdiomake help lists every target.
Running the server
stdio (default — for MCP clients that launch the server)
uv run random-mcp-server
# or
make runStreamable HTTP (for networked clients / containers)
make run-http # PORT defaults to 8000
PORT=9000 make run-httpInspect the server
make inspect # print a summary: name, version, tool count
make dev # launch the interactive FastMCP Inspector (web UI)Configuration
All configuration is via environment variables:
Variable | Default | Purpose |
|
| Name reported by |
|
| Records generated per kind at start-up |
| (random) | Fixed seed for reproducible pools |
| (off) | Expose the |
|
|
|
|
| Bind address for |
|
| Bind port for |
ALLOW_REGENERATE accepts 1/true/yes/on (case-insensitive) to enable.
Using with an MCP client — local development (from source)
This section is for developers working from a checkout of this repo. It runs the server straight from your local source via uv, so code changes take effect on the next launch. If you only have the Docker image or a remote deployment, skip to Using a published image or a remote server.
Point a stdio-based client (e.g. Claude Desktop, Claude Code) at the console
script. Example claude_desktop_config.json entry using uv:
{
"mcpServers": {
"random": {
"command": "uv",
"args": ["run", "--directory", "/absolute/path/to/random-mcp-server", "random-mcp-server"]
}
}
}With Claude Code:
claude mcp add random -- uv run --directory "$PWD" random-mcp-serverConfirm it's connected with claude mcp list (or /mcp inside a session).
Example prompts (Claude Code)
Once the server is added, just ask in plain language — Claude picks the right tool. The tool it invokes is shown in parentheses.
"Is the random server up? What version is it?" → (
server_info)"Give me 3 random people." → (
list_recordswithkind="people",count=3)"Show me the first random person." → (
get_recordwithkind="people",id=1)"How many random coordinates are available?" → (
count_recordswithkind="coords")"List all the random words." → (
list_recordswithkind="words")"Grab 5 random coordinates and drop them on a map." → (
list_recordswithkind="coords",count=5)"Reseed the random data with seed 42, then show me person 1." → (
regeneratewithseed=42, thenget_record)"Reshuffle all the random records." → (
regenerate)"Get random value number 4." → (
get_recordwithkind="values",id=4)
Handy because records are seeded and stable: ask for a person by id, use it to seed a test fixture, and it stays the same until you ask Claude to reseed. Pass a fixed seed (e.g. "reseed with 42") when you need reproducible data.
The two regenerate prompts only work when the server was started with
ALLOW_REGENERATE=1 (the opt-in flag);
otherwise the tool isn't exposed and Claude won't have it to call.
Using a published image or a remote server
This section is for consumers who are not building from source — you have the published Docker image, or someone has deployed the server for you. No Python, uv, or checkout required. Pick the option that matches how the server reaches you.
Option A — Docker image, client launches it (stdio)
The client starts a fresh container per session and talks to it over stdio. Use
-i (keep stdin open) and force the stdio transport, since the image defaults to
HTTP. The image is published to two registries, so pick one:
// GitHub Container Registry (GHCR)
{
"mcpServers": {
"random": {
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT=stdio",
"ghcr.io/mitchallen/random-mcp-server:latest"]
}
}
}// Docker Hub
{
"mcpServers": {
"random": {
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT=stdio",
"mitchallen/random-mcp-server:latest"]
}
}
}Claude Code equivalent — again, pick a registry:
# GitHub Container Registry (GHCR)
claude mcp add random -- docker run -i --rm -e MCP_TRANSPORT=stdio ghcr.io/mitchallen/random-mcp-server:latest
# Docker Hub
claude mcp add random -- docker run -i --rm -e MCP_TRANSPORT=stdio mitchallen/random-mcp-server:latest(Pin a version like :0.1.3 in place of :latest for a reproducible setup.)
Scope — local (default) vs user. claude mcp add registers the server
in the current project only. Add --scope user (-s user) to register it once
for every project on your machine instead:
# GHCR, available across all your projects
claude mcp add --scope user random -- docker run -i --rm -e MCP_TRANSPORT=stdio ghcr.io/mitchallen/random-mcp-server:latest
# Docker Hub, available across all your projects
claude mcp add --scope user random -- docker run -i --rm -e MCP_TRANSPORT=stdio mitchallen/random-mcp-server:latest(Scopes are local — this project, the default; project — shared via a
checked-in .mcp.json; and user — all your projects.)
Option B — Long-running container over HTTP (local)
Start the container once (it serves HTTP by default) from either registry, then point an HTTP-capable client at it:
# GitHub Container Registry (GHCR)
docker run -d --rm -p 8000:8000 --name random-mcp ghcr.io/mitchallen/random-mcp-server:latest
# Docker Hub
docker run -d --rm -p 8000:8000 --name random-mcp mitchallen/random-mcp-server:latestClaude Code (native HTTP transport) — the client connects over HTTP, so the command is the same regardless of which registry you pulled from:
claude mcp add --transport http random http://localhost:8000/mcpAdd --scope user (-s user) to register it for every project on your
machine instead of just the current one:
claude mcp add --scope user --transport http random http://localhost:8000/mcpFor clients that only speak stdio, bridge to the HTTP endpoint with
mcp-remote:
{
"mcpServers": {
"random": {
"command": "npx",
"args": ["-y", "mcp-remote", "http://localhost:8000/mcp"]
}
}
}Option C — Remote deployment (HTTP)
If the server is hosted elsewhere, use its public URL — everything else matches Option B. There's no image to pull here (the host already runs it, from whichever registry they chose), so registry choice doesn't apply on your side:
claude mcp add --transport http random https://random-mcp.example.com/mcpAdd --scope user (-s user) to register it across all your projects:
claude mcp add --scope user --transport http random https://random-mcp.example.com/mcp{
"mcpServers": {
"random": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://random-mcp.example.com/mcp"]
}
}
}Notes for remote use:
Prefer HTTPS so traffic (and any auth headers) are encrypted in transit.
This server ships no authentication (the REST server's
x-api-keyguard isn't ported). If you expose it beyond localhost, put it behind a reverse proxy, gateway, or network policy that enforces access — or add FastMCP auth.No built-in rate limiting — by design (see below).
The endpoint path is
/mcp(no trailing slash). Requesting/mcp/works too but returns a 307 redirect to/mcp, so point clients at/mcpto skip the extra round-trip.
Why there's no built-in rate limiting
FastMCP ships rate-limiting middleware and it would be a few lines to wire in, but this server deliberately doesn't:
Nothing expensive to protect. Every tool is an in-memory lookup against a pool built once at start-up — no database, external API, or real compute cost. Rate limiting shields scarce resources; this workload has none.
It only makes sense on the shared HTTP transport. Over stdio each client launches its own process, so throttling your own single-user server is moot.
Without auth there's no per-client identity to key on. In-memory limiting would fall back to a global limit, which recreates the shared-instance fairness problem (one noisy client starves everyone) rather than solving it. It also wouldn't coordinate across replicas behind a load balancer.
The edge is the right layer. For a public deployment, enforce rate limits at the same reverse proxy / gateway that provides auth and TLS (nginx, Cloudflare, an API gateway) — it coordinates across replicas and can key on authenticated identity. App-level limiting becomes worthwhile mainly once you add auth (so
get_client_idis meaningful).
The example prompts above work the same once the server is connected by any of these methods.
Verified client setups
The setups below were exercised against the published image (:0.1.3) with a
real client — connect, initialize, list tools, and call a tool — not just
assumed. Legend: ✅ connected end-to-end · ☑️ server/endpoint proven, that exact
client wiring not run here.
Setup | Transport | How it was verified | Status |
Docker image, client-launched (Option A) | stdio | Piped an MCP | ✅ |
Long-running HTTP container (Option B) | HTTP | FastMCP network client against | ✅ |
Long-running HTTP container, Claude Code | HTTP |
| ✅ |
Local dev, console script (from source) | stdio | Server proven through the in-memory FastMCP client and the test suite; the | ☑️ |
Remote deployment (Option C) | HTTP | Identical to Option B but with a public URL; the HTTP endpoint is proven, a hosted instance was not stood up. | ☑️ |
stdio-only client via | HTTP (bridged) | Documented from standard | ☑️ |
Docker
Published multi-platform (linux/amd64, linux/arm64) images are available
from two registries:
GitHub Container Registry:
ghcr.io/mitchallen/random-mcp-serverDocker Hub:
mitchallen/random-mcp-server
The image runs the server over streamable HTTP by default (MCP_TRANSPORT=http,
HOST=0.0.0.0, PORT=8000) so it's reachable on a published port.
It's built on a distroless Chainguard/Wolfi
Python base — no shell or package manager, runs as a non-root user, and scans
0 known vulnerabilities. Every build is gated by a Trivy scan (fails on
fixable CRITICAL/HIGH) and the published :latest is re-scanned daily; see
CI / Publish.
Pull the image
docker pull ghcr.io/mitchallen/random-mcp-server:latest
# or from Docker Hub
docker pull mitchallen/random-mcp-server:latestBoth registries also publish version tags (e.g. :0.2.4); prefer a pinned
version over :latest for reproducible deployments.
Run the container
docker run --rm -p 8000:8000 --name random-mcp ghcr.io/mitchallen/random-mcp-server:latestThen connect an HTTP MCP client to http://localhost:8000/mcp.
Test a published release with make
Convenience targets pull and run the published image in your local Docker environment — handy for smoke-testing a release without a local build:
make docker-test # up + smoke + down in one shot (exits non-zero on failure)
make docker-up # pull + run ghcr.io/mitchallen latest, detached
make docker-smoke # MCP `initialize` handshake — passes if the server responds
make docker-logs # follow the container logs
make docker-down # stop it
make docker-up TAG=0.1.1 # pin a version
make docker-up REGISTRY=docker.io/mitchallen # pull from Docker Hub instead
make docker-up HTTP_PORT=9000 # publish on a different host portConfigure at runtime
Pass any of the configuration variables with -e:
docker run --rm -p 9000:9000 \
-e PORT=9000 \
-e APP_NAME=my-random \
-e RANDOM_COUNT=50 \
-e RANDOM_SEED=42 \
ghcr.io/mitchallen/random-mcp-server:latestTo run over stdio inside the container instead (e.g. when another process attaches to it), override the transport:
docker run --rm -i -e MCP_TRANSPORT=stdio ghcr.io/mitchallen/random-mcp-server:latestBuild locally
make docker-build # docker build -t random-mcp-server .
make docker-run # serves http on localhost:8000CI / Publish
Two GitHub Actions workflows live in .github/workflows/:
test— runs on every push/PR tomain: the unit suite (uv sync --frozenthenpytest --ignore=tests/test_bdd.py).bdd— runs on every push/PR tomainin its own workflow: the pytest-bdd scenarios (pytest tests/test_bdd.py), so they pass or fail and report (and badge) independently of the unit suite.publish— triggered by pushing av*tag. Builds a multi-platform (linux/amd64,linux/arm64) image and pushes it to the GitHub Container Registry asghcr.io/mitchallen/random-mcp-serverwith both the version andlatesttags, then runsmake docker-testagainst the just-published image as a post-publish smoke check (the job fails if the released image doesn't answer an MCPinitialize). It uses the built-inGITHUB_TOKEN, so no extra secrets are needed.publish-dockerhub— also triggered by av*tag. Pushes the same multi-platform image to Docker Hub asmitchallen/random-mcp-server, runs the samemake docker-testpost-publish smoke check against it, and syncs this README to the Docker Hub repo description. Requires two repository secrets and a pre-created Docker Hub repository (see below).
Docker Hub setup
The publish-dockerhub workflow needs:
A Docker Hub repository named
mitchallen/random-mcp-server.Two repository secrets — set them with the GitHub CLI:
gh secret set DOCKERHUB_USERNAME --repo mitchallen/random-mcp-server gh secret set DOCKERHUB_TOKEN --repo mitchallen/random-mcp-server # a Docker Hub access token
Until both secrets exist, the publish-dockerhub job will fail on tag pushes
while the GHCR publish job continues to work on its own.
To cut a release, use the release target — it bumps version in
pyproject.toml (and uv.lock), commits, tags, and pushes, which triggers both
publish workflows:
make release # patch bump (default)
make release BUMP=minor # or minor / majorThe target refuses to run unless the working tree is clean and you're on main.
It's equivalent to bumping the version, then git tag vX.Y.Z && git push origin main vX.Y.Z by hand.
Development
Source:
src/random_mcp_server/generators.py— deterministic, seedable record builders (RandomFactory)server.py— FastMCP tools + entry point (main)
Tests:
tests/, run withmake test(uv run pytest), driven through an in-memory FastMCP client. Two layers:test_generators.py/test_server.py— plain pytest unit tests.test_bdd.py+tests/features/*.feature— a pytest-bdd layer that mirrors random-server's Cucumber features (Gherkin scenarios for each record kind and the server info check), plus scenarios forget_record(by id, stability, out-of-range),count_records, andregenerate(seed reporting and reproducibility). The/v1/<kind>routes map to thelist_records/get_record/count_recordstools;auth.featureis not mirrored since thex-api-keyguard isn't ported.
make buildproduces a wheel/sdist viauv build.Dependencies:
uv.lockis committed and the Docker build installs from it with--frozen. Whenever you change dependencies inpyproject.toml, runmake lock(oruv lock) to refresh the lockfile and commit it.
FastMCP integration notes
Two non-obvious adjustments were needed so the FastMCP tooling reports the project correctly:
Explicit
version.FastMCP(...)is constructed withversion=APP_VERSION(read from the installed package metadata). Without it, FastMCP falls back to reporting its own framework version in the MCPinitializehandshake and inmake inspect/fastmcp inspect— so the server would advertise e.g.3.4.3instead of the package's0.1.2.Absolute import in
server.py. The module imports its siblings asfrom random_mcp_server.generators import ...rather thanfrom .generators. The FastMCP CLI (make inspect,fastmcp list/call) loadsserver.pyby path rather than as part of the installed package, and a relative import fails that way withattempted relative import with no known parent package. The absolute form loads correctly both by path and as a package module.
License
MIT © Mitch Allen
Available Tools
4 toolscount_recordsA
Return the number of records available for kind (the /count route).
| Name | Required | Description | Default |
|---|---|---|---|
| kind | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden for behavioral disclosure. It only states the basic operation (returning count) and the route, but omits details such as error handling, performance implications, or any side effects. This leaves agents with limited understanding of the tool's behavior beyond its core function.
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 that conveys the core purpose efficiently. It adheres to front-loading by placing the verb 'Return' at the beginning, and contains no extraneous information.
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?
For a simple counting tool with a single enum parameter and an existing output schema, the description provides sufficient completeness. It identifies the key input and the action, leaving detailed return-value structure to the output schema. However, it could be improved by noting that an invalid 'kind' may cause an error.
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?
The schema has one parameter 'kind' with enum values, but the description does not explain the meaning of each value or provide any additional context. Since schema description coverage is 0%, the description should compensate, but it merely restates the parameter name without enriching its semantics.
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 clearly states the tool's function: returning the number of records for a given 'kind', and explicitly mentions the `/count` route. It effectively distinguishes from sibling tools like 'list_records' and 'get_record' by focusing on counting rather than fetching data.
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?
No explicit when-to-use or when-not-to-use guidance is provided. The context of sibling names implies usage for counting instead of listing or getting records, but the description does not articulate conditions for choosing this tool over alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_recordA
Return a single record from kind by 1-based id (the /:id route).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | ||
| kind | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden. It implies a read operation, mentions 1-based indexing, but does not disclose auth requirements, error behavior, or confirm it is non-destructive.
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 concise sentence. The route mention provides context but is slightly redundant.
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 the output schema exists, description does not need to cover return values. It covers the core functionality for a simple get operation, though missing error scenarios.
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?
The description adds that id is 1-based, which is not in the schema. But for kind, it only repeats the parameter name. With 0% schema coverage, more detail would be beneficial.
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 clearly states 'Return a single record' with the specific parameters kind and id. It distinguishes from siblings like list_records which return multiple records, and count_records which returns counts.
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?
It mentions the 1-based id and the route pattern, implying RESTful usage. However, it does not explicitly state when to use this versus list_records or count_records.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_recordsA
Return the seeded pool of records for kind.
Pass count to cap how many are returned (from the front of the pool);
omit it to return the whole pool. empty always returns [].
| Name | Required | Description | Default |
|---|---|---|---|
| kind | Yes | ||
| count | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must cover behavior. It states the return value and special case for 'empty' kind, but does not disclose idempotency, side effects, or safety. Since it is a read operation, it is adequate but could be more explicit.
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 concise with three sentences, front-loading the purpose. Each sentence adds meaningful information without redundancy.
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 the tool's simplicity and presence of an output schema, the description covers core behavior, parameter usage, and the 'empty' special case. It lacks details on error handling or ordering beyond 'front of the pool', but is largely sufficient.
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 adds value. It explains that 'count' caps the returned records from the front, and that 'empty' kind returns []. However, it does not elaborate on 'kind' beyond naming it, leaving some ambiguity.
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 clearly states it returns a 'seeded pool of records' for a given 'kind', using a specific verb. It differentiates from siblings like 'count_records' and 'get_record' by implying this tool returns a list.
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 explains parameter usage (count, empty) but does not explicitly state when to use this tool over siblings like 'count_records' or 'get_record'. The context is implied but lacks direct guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
server_infoA
Health/status of the server (the REST server's GET / route).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It describes a read-only operation (health/status) via a GET route, which is non-destructive and safe. While it doesn't detail the specific fields returned (handled by output schema), the behavioral nature 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.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that is clear and to the point. No unnecessary words or redundancy. It front-loads the action and resource efficiently.
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 zero parameters and the presence of an output schema, the description is largely adequate. It tells what the tool does. Minor improvement could mention it returns server health status, but it's sufficient.
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?
The tool has no parameters, and schema coverage is 100% (empty object). With no params, the description doesn't need to add parameter meaning; baseline 4 is appropriate.
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 clearly states the tool returns 'Health/status of the server' via the REST server's GET / route. It specifies the verb (get health/status) and resource (server), and distinguishes it from sibling tools that deal with records.
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?
No explicit when/when-not/alternatives are given. However, the context of sibling tools (count_records, get_record, list_records) implies this is for server health, not data operations. Usage is implied but not explicitly defined.
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. Dates show when Glama detected each change.
4 tool updates
v0.2.3- First observed
count_records - First observed
get_record - First observed
list_records - First observed
server_info
TDQS
Each tool has a distinct purpose: counting records, retrieving by ID, listing with options, and server health. No ambiguity among them.
Most tools follow verb_noun pattern (count_records, get_record, list_records), but server_info deviates as a noun_verb? phrase, causing minor inconsistency.
Four tools is well-scoped for a simple read-only data server, each tool earns its place without unnecessary complexity.
The server covers basic read operations (list, get, count) but lacks create, update, delete functionalities, leaving notable gaps for a full data API.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
A simple MCP server built with FastMCP and python
A basic MCP server to operate on the Postman API.
Related MCP Servers
- MIT
- AlicenseNot gradedqualityDmaintenanceA simple MCP server that provides tools for generating unique IDs in several formats, useful for when you need an LLM to create data containing new IDs.Eclipse Public 2.0
- FlicenseAqualityDmaintenanceAn MCP server that provides tools to interact with the JSONPlaceholder fake REST API for testing and prototyping, supporting CRUD operations on posts, comments, todos, and users.7-
- AlicenseNot gradedqualityCmaintenanceAn MCP server that answers one question well: 'has this JSON changed since I last saw it?'MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/mitchallen/random-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server