oncall-router-mcp
With this server, an AI assistant can answer incident-response questions from a local on-call catalog: who owns a service, who to escalate to and by when, what runbook steps to try first, and where the incident stands on the impact clock.
who_owns: resolve a service name or alias to the owning team and contact info; if not found, it returnsfound=falseand near-match suggestions instead of guessing.escalation_path: get the ordered escalation chain for a service/severity, with the minute each hop is due measured from impact start; unknown severities are refused.playbook: retrieve runbook steps for a service (optionally by symptom); if the symptom is unknown, fall back to general steps and setfell_back=true.impact_clock: givenimpact_startand an explicitnow, determine which escalation hop should be active and what is overdue, measured from impact start rather than ticket creation.mttx_review(described in README): analyze post-incident timestamps to measure Detect/React/Mitigate phases, report unmeasured phases, and identify the dominant phase.The server is local and deterministic: it reads a TOML catalog, makes no network calls or state changes, and every tool fails closed rather than guessing.
Click on "Deploy 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., "@oncall-router-mcpwho owns the api-gateway service?"
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.
oncall-router-mcp
An MCP server that answers the three questions that eat the first ten minutes of an incident: who owns this, who do I wake and by when, and what does the runbook say to try first. Plus a fourth that most tools get wrong, which is where should we be on the clock right now, measured from when impact started rather than from when somebody opened a ticket.
What this is
A small program that reads one text file about your services and answers five questions for an AI assistant: who owns this, who to wake and by when (escalation: the next person to call when the first does not answer), what to try first, which escalation step should be active by now, and, the day after, which phase of the incident ate the minutes. It never pages anyone or changes anything; it only answers. In jargon, an MCP server. MCP is the Model Context Protocol, a published standard for how an assistant plugs into outside tools, the way a wall socket is a standard for plugging in appliances. This one speaks the protocol by hand, three message types and no library, and its own source says a production deployment would use the official one.
Related MCP server: runframe-mcp-server
Why it matters
At 2am the first minutes of an incident go to finding who to call and what to try, not to fixing anything, because that knowledge sits in three places: a wiki nobody updated, a rotation tool that knows only this shift, and whoever has been there longest. This puts it in one file your assistant can read, and it would rather say "I do not know" than guess: a confident wrong page costs more than an honest refusal.
Try it
Clone the repo (download a copy) and, inside it, run these three lines. Run on 2026-09-01 with Python 3.12.10 on Windows 11: the tests took 2.32 seconds; the clone and the install depend on your network and were not timed.
python -m pip install "pytest>=7,<10"
python -m pytest tests/ -q
PYTHONPATH=src python -m oncall_router.server --catalog catalog.tomlLine 1 installs pytest, the test runner and the only package the repo asks you to install. Line 2 runs the tests (count and caveat below). Line 3 starts the server, which waits silently for questions: correct, not a hang. On PowerShell that line is $env:PYTHONPATH="src"; python -m oncall_router.server --catalog catalog.toml. Asking who_owns with {"service": "cart"} answered checkout and its on-call handle, the name you would page (invented sample data). Wiring it into an assistant such as Claude Desktop or Claude Code is described below; no test in the repo exercises that wiring.
How it works, intuitively
Picture the phone tree taped beside an office phone. This program is that sheet with one extra column: deadlines counted from when customers began hurting, not from when the ticket was opened. The sheet does not dial; neither does this.
It loads the catalog once at start-up. The catalog is one plain-text file in TOML format, chosen because Python reads TOML with nothing extra installed. Per question it maps nicknames like "cart" to "checkout", walks the call order adding up minutes against the elapsed time you supplied (it never reads the wall clock; a search of the source finds no call to the system time), and writes one line back. An unknown name gets found false plus near-misses, never a guess.
What the numbers mean (and what they do not)
Each number carries its measurement and its limit in the same sentence. Checkable means you can rerun it from a clone; asserted means you are taking my word for it. The three below are checkable; the date and machine they were run on are asserted.
82 tests passed in one run of pytest on 2026-09-01. The repo's own setup instructions print no count on purpose, because it rises with every test added, so 82 holds for that date only. All 82 were written on the author's side, so they check what the author thought to check: green is a ceiling on what the suite can promise, not a proof the code is right.
5 tools, confirmed by a live tools/list call (the protocol's "what can you do" question) and by a test that pins the exact set. The rubric, the pass-or-fail list frozen before the code, scoped four; mttx_review was added 2026-08-24 under a separate frozen extension, and the rubric file says so.
0 runtime dependencies (nothing to install beyond Python 3.11 or newer) and no network calls in the source. Both are enforced by tests that read the text of the src/ folder: one rejects any import outside a short list of Python's own modules, the other fails if the source names any of five networking names. A text scan proves those words are absent; it is not a run watched with the network cable pulled.
Where it loses
The repo names its edges: "No live integrations." "No write actions." "The shipped catalog is fictional." "The timing model is a convention, not a standard." Two claims it cannot prove: that every test was seen failing before its code existed (CI, the robot that reruns the tests on every push, cannot enforce history, and a log of 6 commits, the saved snapshots of the code, cannot show a per-test fail-then-pass sequence), and the headless assistant run described below, a run with no human at the keyboard, which nothing in the repo tests (one recorded run sits in docs/HEADLESS-RUN-2026-09.md, a receipt, not a test). One edge found by running it: pipe questions in by hand from a PowerShell set to UTF-8 output and the first line arrives with an invisible marker some Windows tools prepend to text, so the server skips that line without a word; the same lines from a plain file were all answered, and assistant clients do not send the marker.
Try your own case
For your own file, copy catalog.toml, edit its services, teams and call orders, and run PYTHONPATH=src python -m oncall_router.server --catalog your.toml. To add a test, copy one row of the table of cases in tests/test_server.py (lines 48-67), change its inputs and expected output, and rerun pytest. The hygiene tests, the ones that police the text rather than the behaviour, scan every text file in the repo except the scanner itself: hyphens only, no key-shaped strings, none of nine marketing phrases.
For engineers
Everything below is the original technical README: the design, the measurements, and how to reproduce them.
No runtime dependencies, no API key, no network calls, no telemetry. It reads one local file. pytest is needed only to run the gates.
Explained simply
Picture the wall next to an old fire-station telephone. Taped to it is a laminated card: which crew covers which district, who to call when the first call goes unanswered, and what to do first for each kind of fire - with the minutes printed beside each name, so you know when an unanswered call becomes the next call. Every firehouse has one, because at 2am nobody should be remembering - they should be reading.
This server is that laminated card for your software, written so an AI assistant can read it for you while your hands are busy. That is all MCP (Model Context Protocol) is: a standard socket that lets an assistant plug into outside tools. This repo is one small plug. It puts your team's on-call knowledge - owners, escalation chains, runbook first moves, expected timings - where the assistant you already use can reach it.
The knowledge itself usually lives in three places: a wiki nobody updated, a rotation tool that only knows the current shift, and the head of whoever has been there longest. At 2am the expensive minutes go to working out who to call, not to fixing anything. This moves those minutes back where they belong.
What this looks like during a real incident
It is 2:47am. Your monitor fires: checkout error rate 40% for six minutes. You open your assistant, paste the alert, and ask for a first-ten-minutes brief. With this server connected, the assistant can answer from your catalog instead of from its imagination:
"Who owns this?" -
who_owns("cart")resolves the alias (nobody typescheckout-service-v2at 2am) and returns the Storefront team with the primary on-call handle and their coverage hours."Who do I wake, and by when?" -
escalation_path("checkout", "sev1")returns the full chain in order - primary at minute 5, secondary at minute 15, engineering manager at minute 30, then up into Platform Incident Command - because a sev1 climbs all the way and a sev3 deliberately does not."What do I try first?" -
playbook("checkout", "declines")returns the two moves written for that exact symptom, starting with splitting declines by payment method, because one failing method hides inside an overall rate."Where should we be on the clock?" -
impact_clocktakes when impact started and what time it is now, and answers which escalation hop should already be active and what is overdue - measured from impact start, not from when the ticket was opened.
Every answer above is what the shipped sample catalog actually returns, word for word in structure. The full JSON for every tool, including the failure paths, is in docs/TRANSCRIPT.md - and CI regenerates that file on every push and fails the build if it drifts from what the code actually produces. The docs cannot lie about the code.
Wire it into your production alert flow
Three patterns, from zero setup to fully automated. In all three the server only ever answers questions - it never pages anyone and never changes state, so the human stays in command.
1. Paste the alert (zero setup beyond the config below). Alert lands in your phone, you paste it into Claude Desktop or Claude Code with this server connected, together with this prompt:
A production alert just fired. Alert text: <paste the alert here>.
Using only the oncall-router tools, give me a first-ten-minutes brief:
1. Which service is this and who owns it (who_owns - try the name the alert uses).
2. Who do I wake and by when (escalation_path - I will give you the severity).
3. The first three moves (playbook - match the symptom; say if you fell back to general).
4. Where we are on the clock (impact_clock - impact started at <time>, it is now <time>).
Report exactly what the tools return. If a tool says found=false, say so - do not guess.2. Trigger it from the alert itself (headless). Any alerting webhook can hand the
payload to a headless assistant run, and the brief is drafted before you have found your
glasses. Save the JSON config from the setup section below as oncall.mcp.json - same
shape, same paths:
claude -p "PRODUCTION ALERT: 'checkout error rate 40% for six minutes'. Impact start
02:41Z, now 02:47Z, severity sev1. Use the oncall-router tools to write a
first-ten-minutes brief: owner, escalation order with due minutes, first three runbook
moves, current hop on the clock. Only report what the tools return." \
--mcp-config oncall.mcp.json \
--allowedTools "mcp__oncall-router__who_owns,mcp__oncall-router__escalation_path,mcp__oncall-router__playbook,mcp__oncall-router__impact_clock"The --allowedTools grant is not optional: a headless run has nobody to answer a
permission prompt, so without it the assistant can see the tools and use none of them.
The names follow mcp__<server>__<tool>, where <server> is the key you chose in the
JSON config (oncall-router above).
claude -p writes the brief to stdout; piping that into your chat tool's incoming
webhook is the one line left to you, on purpose. Two honest notes: the server stays
keyless, but the assistant running it authenticates as itself; and the same pattern works
with the Claude Agent SDK or any MCP-speaking agent runner. The assistant drafts the
brief; a human decides what to do with it. That division of labor is deliberate and this
server enforces its half of it.
3. The day after (see "After the incident" below). Feed mttx_review the timestamps
you actually have and learn which phase ate the incident - so next month's 2:47am is
shorter than this one's.
The five tools
tool | answers | when it cannot |
| which team owns a service, and how to reach them now | says so, and offers near matches as candidates rather than as an answer |
| who to wake, in order, with the minute each hop is due | refuses an unknown severity rather than defaulting to the quietest one |
| what the runbook says to check first | falls back to the service's general steps and sets |
| which hop should be active now, and what is overdue | requires an explicit |
| where the minutes went - Detect, React, Mitigate - and which tool shrinks the worst phase | measures only phases whose endpoints were supplied; refuses out-of-order timestamps by name |
Every tool fails closed. A near miss never silently resolves, because a confident wrong escalation at 2am costs more than an honest "I do not know".
Run it in sixty seconds
git clone <this repo> && cd oncall-router-mcp # Python 3.11+ (tomllib is stdlib from 3.11)
python -m pip install "pytest>=7" # the only dependency, and only to run the tests
python -m pytest tests/ -q # run the gates; the count is whatever pytest reports, never a number this file maintains
PYTHONPATH=src python -m oncall_router.server --catalog catalog.tomlOn PowerShell, the last line is: $env:PYTHONPATH="src"; python -m oncall_router.server --catalog catalog.toml
To wire it into Claude Desktop or Claude Code, add this to your MCP client config, using absolute paths:
{
"mcpServers": {
"oncall-router": {
"command": "python",
"args": ["-m", "oncall_router.server", "--catalog", "/abs/path/to/catalog.toml"],
"env": { "PYTHONPATH": "/abs/path/to/oncall-router-mcp/src" }
}
}
}"command" must resolve to a Python 3.11 or newer. Desktop clients do not inherit your
shell's PATH, so on macOS especially, replace "python" with the absolute path from
which python3 - and note that /usr/bin/python3 is Apple's 3.9 stub, which is too old.
On Windows, use the full path to your python.exe.
To use your own data, copy catalog.toml, edit it, and pass --catalog yours.toml. No
code changes: the catalog is data, and a test proves it by running the same tool against
two different catalogs. Editing one readable file is the entire onboarding cost for a new
team.
The catalog
One TOML file holding services, the team that owns each, escalation chains with timings,
and runbook steps by symptom. TOML rather than YAML because tomllib ships in the Python
standard library, so the catalog costs this project zero dependencies.
Aliases matter more than they look. During an incident people type the name they remember,
not the name in the repo: cart, buy button and the checkout all resolve to
checkout, the same way gateway and apigw resolve to api-gateway. Nobody types
checkout-service-v2 at 2am, and a router that only answers to the formal name has
already cost you a minute.
After the incident: where did the minutes go
The four tools above serve the first ten minutes. The fifth, mttx_review, serves the
day after. Give it the timestamps you actually have - when impact started, when anyone
first knew (Detect), when a responder engaged (React), when customers stopped
feeling it (Mitigate) - and it measures each phase, names the one that ate the
incident, and points at the tool or practice that shrinks it next time. React dominant?
The minutes went to finding the right person, which is what escalation_path exists to
fix. Mitigate dominant? The first three moves belong in the runbook, which is what
playbook serves. Detect dominant? The tool says honestly that detection lives in your
alerting, not in this server.
Three design choices worth naming. A phase is measured only when both of its endpoints
were supplied - a missing milestone is reported as unmeasured, never interpolated. A
still-open incident requires an explicit now and gets told which phase is bleeding
right now. And there is no grade, deliberately: thresholds for a "good" MTTx vary by an
order of magnitude across teams and tiers, so the shares and the dominant phase are
reported as facts and the judgment stays with the team that owns the service.
Why it is built this way
The design opinion in the code is that escalation timing runs from impact start. A ticket opened twenty minutes late does not buy the responder twenty extra minutes, and a tool that measures from ticket creation will quietly tell you that it does.
The second opinion is that at 2am, "I do not know" beats a plausible guess, every
time. That is why unknown services return candidates instead of a best match, why an
unknown severity is refused instead of defaulted, and why a missing timestamp becomes
unmeasured instead of an interpolation. An assistant wired to this server inherits that
honesty: it cannot confidently misroute you, because the tool underneath refuses to.
What this deliberately does not do
No live integrations. It does not read your incident tool, your rotation tool, or your monitoring. Those are per-customer decisions and they belong behind a boundary.
No write actions. It never pages anyone, opens anything, or changes state. It answers questions and a human decides.
The shipped catalog is fictional. Every service, team, and handle in
catalog.tomlis invented. A test fails the build if anything employer-identifying appears in the repo.The timing model is a convention, not a standard. Cumulative minutes from impact start, carried forward when the chain climbs to another team. Reasonable, and not the only reasonable choice.
No cost or latency figures, because there are no model calls. The server is deterministic and local.
Gates
Built against a rubric frozen before the first line of code - published in full, with its publication edits disclosed, as docs/RUBRIC.md. The gates CI enforces, worth knowing:
Every tool answers through a real client speaking the wire protocol, not just as a function call in a test.
Every tool has a failure-path test proving it declines rather than guesses.
Swapping the catalog changes every answer with no code edit, proven by a test.
The committed transcript regenerates, or the build fails.
One malformed client message never ends the session, and errors never leak the deployment path.
The whole suite runs in CI on Linux and Windows on every push.
No credentials, no network calls in the source, no employer content, no third-party imports. This gate blocks.
One process claim sits outside that list on purpose: tests were written and observed failing before each implementation existed. CI cannot enforce history, so that is an assertion you audit rather than a gate a build proves - the commit trail is the closest thing to evidence it has.
Who built this
Built by an SRE lead who carries a real pager and wanted the first ten minutes back. Part of a public, CI-verified portfolio where every published number regenerates or the build fails: lzbiala.github.io
MIT licensed. Copy the catalog, keep the fail-closed defaults, make it yours.
Available Tools
4 toolsescalation_pathA
Who to wake for this service at this severity, in order, with the minute each hop is due measured from impact start. Refuses an unknown severity rather than defaulting to the quietest one.
| Name | Required | Description | Default |
|---|---|---|---|
| service | Yes | ||
| severity | Yes | A severity defined by the catalog, for example sev1. |
TDQS
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 a non-default behavior ('Refuses an unknown severity rather than defaulting to the quietest one') and describes the output nature (ordered list with minute timings). No other side effects are mentioned, but the tool appears read-only and the disclosure is sufficient for a simple query.
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?
Two concise sentences, front-loaded with the core purpose and output, followed by the refusal behavior. Every word earns its place, with no redundancy or fluff.
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 tool with only 2 simple parameters and no output schema, the description covers the essential return value (who, order, timing) and the key behavioral nuance (refusal on unknown severity). Nothing critical is missing given the tool's simplicity, though explicit error handling for unknown service isn't described.
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 coverage is 50% (severity has a description, service does not). The description adds significant meaning to severity: it must be a catalog-defined value and unknown ones are refused. Service is only referenced as 'this service' without additional constraints, but the schema already defines it as a string. Overall, the description compensates well for the coverage gap.
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 states a specific query (who to wake) for a defined resource (this service at this severity) and includes output order and timing. It clearly distinguishes from siblings like who_owns (ownership) and impact_clock (timing) by focusing on the escalation path itself.
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 implies usage ('Who to wake for this service at this severity') but never explicitly says when to use this tool over siblings or when not to use it. No alternatives are named, so an agent must infer from tool names rather than get explicit routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
impact_clockB
Given when impact started, which escalation hop should be active now and which are overdue. Time is measured from impact start rather than ticket creation. Requires an explicit now timestamp: it never assumes the current time.
| Name | Required | Description | Default |
|---|---|---|---|
| now | Yes | ISO 8601. Required. | |
| service | Yes | ||
| severity | Yes | ||
| impact_start | Yes | ISO 8601, e.g. 2026-08-23T14:00:00Z |
TDQS
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 explicitly states that the tool requires an explicit now timestamp and never assumes current time, and that it measures from impact start rather than ticket creation. This is meaningful behavioral context beyond the schema. It does not mention side effects or error conditions, but for a calculation tool this is reasonably transparent.
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 three sentences with no wasted words. It front-loads the purpose, then adds the key behavioral constraint (time basis and explicit now requirement). Each sentence contributes necessary information, making it concise and well-structured.
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 tool with no output schema and no annotations, the description offers the essential purpose and a critical behavioral constraint, but it does not describe the return format, potential error cases, or how severity/service influence the result. It gives enough to understand the intent but lacks detail for full autonomous use.
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 50%, covering 'now' and 'impact_start' but leaving 'service' and 'severity' undocumented. The description reinforces the meaning of impact_start and now but does not explain the roles of service and severity in determining escalation hops. It fails to compensate for the missing schema descriptions, leaving those parameters ambiguous.
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 core function: determining which escalation hop is active and overdue given impact start and a specified now. It also distinguishes time measurement from ticket creation, which is a specific behavioral nuance. However, it does not explicitly differentiate from sibling tools like 'escalation_path' or 'playbook', so it stops short of a 5.
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 provides no guidance on when to use this tool versus its siblings. It mentions a constraint (explicit now timestamp) but does not explain when this tool is appropriate or when another might be better. There is no statement of alternatives or exclusion criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
playbookA
What the runbook says to check first. Falls back to the service's general steps when the symptom is unknown, and says so with fell_back=true.
| Name | Required | Description | Default |
|---|---|---|---|
| service | Yes | ||
| symptom | No | Optional, for example latency. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses a key behavioral trait: when the symptom is unknown, it falls back and reports with fell_back=true. This is valuable and goes beyond simple 'returns steps.' It also implies a read-only operation. However, it does not describe the complete return structure, error handling, or any side effects, though for a read tool this is minor.
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?
Two sentences, no filler. The primary purpose is front-loaded, and the fallback condition is stated concisely with a concrete outcome (fell_back=true). Every word earns its place.
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 two simple parameters and no output schema or annotations, the description provides core information: what it returns conceptually, the fallback condition, and a note about a response field. It omits the exact return payload shape (e.g., list of steps vs. free text), but for a tool this straightforward, it's nearly sufficient. A tiny bit more about the output format would make it a 5.
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 coverage is 50% (only symptom has a description). The description adds meaning by explaining that a missing/unknown symptom triggers fallback behavior, linking symptom to the fallback logic. It clarifies the role of service indirectly via 'service's general steps.' Yet it does not elaborate on allowed values, format, or examples for either parameter beyond what the schema already states for symptom.
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?
States a specific action and resource: retrieving the first checks from a runbook for a service. The description clearly sets it apart from siblings (ownership, escalation, impact) by focusing on runbook guidance. However, 'what the runbook says to check first' is slightly vague about whether it returns a list, a single item, or a message, so it's not a perfect 5.
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 implies usage: use this tool when you need the runbook's first steps, and it handles unknown symptoms by falling back to general steps. It does not explicitly name alternatives or state when not to use it (e.g., if you need escalation path, use escalation_path). The fallback behavior is a form of guidance, but it lacks explicit comparisons to sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
who_ownsA
Which team owns a service and how to reach them right now. Accepts the name someone would actually type during an incident, including aliases. Returns found=false with suggestions rather than guessing at a near match.
| Name | Required | Description | Default |
|---|---|---|---|
| service | Yes | Service name or alias. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It explicitly states 'Returns found=false with suggestions rather than guessing at a near match,' which is a valuable behavioral trait that helps the agent set expectations. It also implies a read-only lookup (no side effects mentioned), though it does not elaborate on authentication or error conditions. Overall, it adds meaningful behavioral context beyond the schema.
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?
Two concise sentences, front-loaded with the primary purpose. Every clause adds value: the first sentence defines the outcome; the second clarifies input flexibility and the non-guessing behavior. No redundancy or filler.
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?
The tool is simple (one parameter, no output schema), and the description covers purpose, input semantics, and a key behavior (found=false with suggestions). It does not list the exact fields returned (e.g., team name, contact info), but 'how to reach them' implies that. Given the low complexity and lack of annotations, it is reasonably complete, though a bit more detail on the return payload would make it excellent.
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 already describes the parameter as 'Service name or alias' with 100% coverage, so the baseline is 3. The description adds nuance by specifying 'the name someone would actually type during an incident,' which gives the agent guidance on the flexibility of input. This extra context—emphasizing natural incident-time phrasing—goes slightly beyond the schema's dry definition, justifying a 4.
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 purpose: 'Which team owns a service and how to reach them right now.' This specifies a verb (owns), a resource (service), and the output (ownership and contact). It distinguishes itself from sibling tools (escalation_path, playbook, impact_clock) implicitly by focusing on ownership rather than escalation steps, runbooks, or timing.
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 implies usage context—when you need to identify who owns a service—but it does not explicitly contrast with siblings or state when not to use this tool. There is no mention of alternatives like escalation_path or playbook. The behavior note about returning found=false provides some guidance, but it is not a clear when-to-use vs. when-not-to-use directive.
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.
4 tool updates
v0.1.0- First observed
escalation_path - First observed
impact_clock - First observed
playbook - First observed
who_owns
TDQS
Scored across 4 tools
Each tool targets a distinct aspect of incident routing: ownership (who_owns), escalation (escalation_path), response steps (playbook), and timing (impact_clock). There is no overlap in purpose, and the descriptions make boundaries clear.
All tool names are lowercase snake_case and are descriptive, but the pattern varies slightly: who_owns is a question-like phrase, while the others are noun compounds. This is a minor inconsistency, but the naming remains intuitive and predictable.
With only 4 tools, the server is tightly scoped to incident routing. Each tool delivers a unique, essential capability without redundancy, making the count ideal for the domain.
The tool set covers the core incident routing workflow: identifying ownership, following escalation paths, accessing playbooks, and tracking escalation timing. Minor gaps like incident acknowledgment or status updates exist but are outside the router's stated purpose.
Maintenance
Related MCP Connectors
Manage incidents and on-call: list/create/update incidents, who is on call, on-call overrides.
Read incidents, services, teams, on-call schedules; acknowledge, resolve and note incidents.
Vendor status pages, TLS cert inspection, DNS propagation checks, and incident-response playbooks.
Manage incident alerts, events, and workflows with custom automations
Related MCP Servers
- FlicenseNot gradedqualityAmaintenanceMCP server for the Rootly incident management platform — alerts, incidents, on-call schedules-

runframe-mcp-serverofficial
AlicenseNot gradedqualityCmaintenanceEnables managing incident response workflows including incidents, on-call, postmortems, and more through the Runframe platform using MCP tools.50 npm4MIT- AlicenseNot gradedqualityDmaintenanceEnables PagerDuty incident response operations including listing incidents, acknowledging and resolving incidents, looking up on-call schedules, and listing services.MIT
- AlicenseNot gradedqualityBmaintenanceSelf-hosted operational dashboard and MCP server that catalogs runnable services and their operational context, offering a read-only MCP endpoint to list projects, service status, runbooks, and reconciliation context.1Apache 2.0