Skip to main content
Glama

ops-toolbox

A small Model Context Protocol server that gives an assistant four things a support engineer actually reaches for: tail a log, check whether an endpoint is answering, search a runbook of past fixes, and write a new fix back into it.

No dependencies. It is plain Node, node server.js and it runs.

What MCP is, briefly

Model Context Protocol is a standard way to hand an AI client a set of tools it can call. The client starts your server as a subprocess and they speak JSON-RPC 2.0 over stdin and stdout, one message per line. The client asks tools/list to find out what exists, then tools/call to run one and get the result back as text.

That is the whole idea. There is no framework requirement, which is why this server has no dependencies: the protocol is small enough to implement directly, and doing it directly makes it obvious what is going on.

Two things matter when you write one:

  • stdout belongs to the protocol. A stray console.log puts a non-JSON line in the stream and the client drops the connection. Every diagnostic in this server goes to stderr, which the client is free to capture or ignore.

  • A tool failing is not a protocol failure. A missing file comes back as a normal result flagged isError, so the model can read the message and correct itself. Protocol errors are reserved for things like an unknown tool name or a missing required argument.

Related MCP server: automation-health-mcp

The tools

Tool

What it does

tail_log

Last N lines of a log file, with an optional case-insensitive filter. Confined to a configured log root.

check_endpoint

Requests a URL and reports status code and latency, so you can tell "running" from "actually answering".

runbook_search

Searches a local JSON runbook of symptoms and their fixes.

runbook_add

Records a new symptom and fix so the next person does not rediscover it.

Two details worth pointing out because they are the kind of thing that bites you in production:

  • tail_log resolves the requested path and rejects anything that lands outside the configured root. A model will happily pass ../../../etc/shadow if you let it.

  • tail_log reads only the last 256 KB of a file rather than the whole thing. A tail of a rotated 4 GB log should not be an out-of-memory error.

  • runbook_add writes to a temp file and renames it over the original. A rename on the same filesystem is atomic, so a crash halfway through cannot leave a truncated runbook behind.

Requirements

Node 20 or newer. Nothing else.

Install

git clone https://github.com/coreyhiggins/mcp-server-example.git
cd mcp-server-example
node selftest.js     # confirm it works before wiring it up

There is no npm install step because there is nothing to install.

Configuration

Both paths come from the environment so the same server can point at sample data during development and at real paths on a server.

Variable

Default

Purpose

OPS_LOG_ROOT

./sample-logs

Directory tail_log is allowed to read from. Set it to /var/log on a real host.

OPS_RUNBOOK

./data/runbook.json

JSON file the runbook tools read and write.

Wiring it into a client

Claude Desktop

Edit the config file, then restart the app.

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "ops-toolbox": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-server-example/server.js"],
      "env": {
        "OPS_LOG_ROOT": "/var/log",
        "OPS_RUNBOOK": "/absolute/path/to/mcp-server-example/data/runbook.json"
      }
    }
  }
}

Use absolute paths. The client does not start the server in your shell's working directory, so a relative path will not resolve the way you expect.

Claude Code

claude mcp add ops-toolbox \
  --env OPS_LOG_ROOT=/var/log \
  --env OPS_RUNBOOK=/absolute/path/to/mcp-server-example/data/runbook.json \
  -- node /absolute/path/to/mcp-server-example/server.js

Then claude mcp list should show it connected.

Driving it by hand

The server is just a program reading lines on stdin, so you can talk to it without any client at all. This is the fastest way to debug one:

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25"}}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
  '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"runbook_search","arguments":{"query":"nginx 502"}}}' \
  | node server.js

Self-test

node selftest.js

20 assertions covering the tools, the JSON-RPC layer, and one real end-to-end handshake against a spawned server over stdio. The HTTP checks hit a throwaway server this script starts on 127.0.0.1, so the test needs no network access. Exits non-zero if anything fails.

Layout

server.js       JSON-RPC plumbing, stdio loop, protocol version negotiation
tools.js        the four tools and their schemas
selftest.js     the one runnable check
data/           seed runbook
sample-logs/    a log file to point tail_log at while you try it

How this is used in production

I run Ubuntu servers where the first ten minutes of any incident are the same three questions: what does the log say, is the service actually answering, and have we seen this before. Those questions are what these four tools are. Putting them behind MCP means I can ask in plain language and get the answer without switching to a terminal, and the runbook grows every time something breaks instead of living in my head.

The security choices in here are not decoration. A tool that takes a file path from a model is an untrusted input path, so it gets a root confinement check, a read cap, and an atomic write. Same review I would give any script that runs on a box with real users on it.

License

MIT

Available Tools

4 tools
check_endpointCheck an HTTP endpointA

Request a URL and report whether it returned the expected status code, plus how long it took. Use it to confirm a service is actually answering, not just running.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesFull http or https URL
timeoutMsNoGive up after this many milliseconds (default 5000)
expectStatusNoStatus code that counts as healthy (default 200)

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 burden. It discloses the core behavior (making a request, checking status, measuring time) and adds the 'answering vs running' context, but omits details like HTTP method, redirect handling, or timeout error behavior, leaving gaps.

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, front-loaded with the action and outcome. No unnecessary words; every phrase 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 HTTP-check tool with fully described parameters and no output schema, the description adequately explains purpose, input, and return meaning. It lacks explicit return format details but is sufficient for this complexity level.

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 coverage is 100%, so the baseline is 3. The description mentions 'expected status code' and timing, which aligns with expectStatus and timeoutMs, but does not add additional meaning beyond what the schema already provides.

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 action ('Request a URL') and the output ('report whether it returned the expected status code, plus how long it took'), clearly distinguishing it from sibling tools like tail_log and runbook_search.

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 gives clear context for use ('Use it to confirm a service is actually answering, not just running'), which implies when to choose this tool, though it does not explicitly mention when not to use it or alternatives.

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

runbook_addAdd a runbook entryA

Record a new symptom and its fix in the local runbook so the next person does not have to rediscover it.

ParametersJSON Schema
NameRequiredDescriptionDefault
fixYesThe steps that resolved it
tagsNoKeywords, for example nginx, mysql, dns
titleYesShort description of the problem
symptomsNoWhat it looks like when it happens

TDQS

A3.5/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 burden of disclosure. It clearly indicates a write operation ('Record') but does not mention whether entries can duplicate, whether it overwrites, or any side effects. Lacks details on idempotency or persistence.

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, clear sentence that is front-loaded with the action and purpose. No wasted words.

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 add operation with fully documented parameters, the description is mostly adequate. However, it lacks context about when to use it versus runbook_search and does not mention the optional tags or symptoms parameters. No output schema means return behavior is undisclosed.

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 mentions 'symptom and its fix', which aligns with the parameters, but adds no additional meaning beyond the schema's own descriptions.

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 the specific verb 'Record' and identifies the resource ('a new symptom and its fix' in 'the local runbook'). It clearly distinguishes from siblings like runbook_search by indicating an add 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 implies usage when someone has discovered a symptom and fix to preserve, but it does not explicitly differentiate from alternatives or state when not to use. No exclusion or comparison to runbook_search is provided.

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

tail_logTail a log fileA

Read the last N lines of a log file under the configured log root, optionally filtered to lines containing a substring (case-insensitive).

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesPath relative to the configured log root, for example nginx/error.log
linesNoHow many lines to return (default 50)
containsNoOnly return lines containing this text

TDQS

A4.2/5.0
Behavior3/5

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

With no annotations, the description carries the burden of disclosing behavioral traits. It explicitly says 'Read' (implying a safe, non-mutating operation) and mentions the 'configured log root' and case-insensitive filtering. However, it does not describe error behavior, return format, or what happens if the path is invalid, which are important for a tool with no structured metadata.

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 primary behavior and includes optional parameters. Every word adds meaning, with no fluff or repeated information from the schema.

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 tool's low complexity, the rich schema descriptions, and the absence of an output schema, the description provides sufficient context for core usage. It does not specify the return format (e.g., array of strings vs. single string), but this is a minor gap for a straightforward log tail operation.

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?

Schema coverage is 100% with clear descriptions for all three parameters. The tool description adds extra value by noting that the 'contains' filter is case-insensitive and that the path is relative to the configured log root, which is not evident from the schema alone. This goes beyond the baseline for well-documented schema.

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 reads the last N lines of a log file under a configured root, with optional case-insensitive substring filtering. This is a specific verb ('Read') and resource ('log file'), and it is distinct from sibling tools like check_endpoint or runbook_search.

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 implies when to use the tool—whenever recent log output is needed. It clearly defines the scope (log root, last N lines) but does not explicitly discuss when not to use it or mention alternatives, though siblings are unrelated and no exclusion is necessary.

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.

  1. 4 tool updatesv1.0.0
    • First observedcheck_endpoint
    • First observedrunbook_add
    • First observedrunbook_search
    • First observedtail_log

TDQS

A3.9/5.0
Disambiguation5/5

Each tool targets a distinct operation: log tailing, endpoint checking, and runbook search/add. There is no overlap in purpose or resource type.

Naming Consistency4/5

Names are clear and readable, but they follow two patterns: verb_noun (tail_log, check_endpoint) and noun_verb (runbook_search, runbook_add). This minor inconsistency is not confusing but prevents a perfect score.

Tool Count5/5

With 4 tools, the set is well-scoped for an operations toolbox. Each tool serves a clear purpose without redundancy or bloat.

Completeness4/5

The set covers the primary operations for its domain: log inspection, endpoint validation, and runbook management (search/add). Minor gaps like runbook deletion exist, but the core workflow is complete.

Maintenance

ActivitySlowing
ResponsivenessNo issues

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

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Small production-oriented MCP server for diagnosing incidents from Elasticsearch logs with unknown schema. It provides tools for log discovery, retrieval, and issue diagnosis.
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    An MCP server for auditing automation health, finding failures, stale logs, and non-functional endpoints that report success while quietly failing.
    7
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Offline MCP server with runbooks for high-volume logs, metrics, traces, and event streams. Search and diagnose symptoms without external dependencies.
    4
    MIT

Latest Blog Posts

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/coreyhiggins/mcp-server-example'

If you have feedback or need assistance with the MCP directory API, please join our Discord server