nginx-certbot-mcp
1-line summary: This is an MCP server that lets AI agents safely manage an nginx reverse proxy and Let's Encrypt certificates through narrow, auditable tools.
Inspect nginx state:
list_sites(domains, upstreams, SSL status),get_site_config(raw config for a domain),reload_nginx(test then reload), andcheck_cert_expiry(certs and days left).Create and manage server blocks:
create_server_block(new site from template with domain, upstream_host, upstream_port) — note this appears in the schema as a renamed version of the README'screate_site.Issue certificates:
issue_cert(viacertbot --nginx, defaults to Let's Encrypt staging, supportsdomain,email,stagingflag).
Provides tools for reading nginx configuration, managing reverse proxy server blocks, reloading nginx, and issuing/renewing SSL certificates via certbot.
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., "@nginx-certbot-mcpcheck the SSL cert expiry for example.com"
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.
nginx-certbot-mcp
Let AI agents manage production web infrastructure without giving them root shell access.
nginx-certbot-mcp provisions Nginx reverse proxies, DNS records, and Let's Encrypt certificates through narrowly scoped, auditable MCP tools — never arbitrary shell commands. Privileged actions go through purpose-built wrappers and least-privilege sudo rules (see Why a wrapper script below).
Architecture

Related MCP server: npm-mcp
Tools
All 23 are implemented and exercised against real infrastructure — see Testing.
Tool | Description |
| List configured nginx server blocks with domain, upstream, and SSL status |
| Raw nginx config for one domain |
| List certbot-managed certs and days until expiry |
| Resolve a domain (CNAME, then A/AAAA) against public resolvers |
| TCP probe of an upstream |
| Whether nginx is running, plus its version |
| Tail access/error logs, capped at 1000 lines |
| List configs archived by |
| Upsert a Route 53 CNAME |
| Delete a Route 53 CNAME — |
| Upsert a Route 53 TXT record, e.g. for ACME DNS-01 |
| Delete a Route 53 TXT record — |
| Create a websocket-capable nginx server block from the default template |
| Rewrite an existing site's |
| Disable, archive, and delete a server block — |
| Re-enable a site from its newest (or a chosen) archive — |
| Delete archives older than N days — |
|
|
| Issue via HTTP-01 ( |
| Issue |
|
|
| Revoke with Let's Encrypt, leaving the files in place — |
| Remove a cert's files from certbot's store — |
Setup
npm install
npm run build
npm run setup -- mcpuserRun the server as a dedicated non-root user (e.g. mcpuser) — never as
root. npm run setup -- <user> (scripts/setup.sh) grants that user
exactly the privileges below, nothing more, and is idempotent: safe to
re-run any time, including after changing the username or pulling an
update that adds a new allowed command.
Required permissions
npm run setup -- <user> installs two things:
/usr/local/bin/nginx-mcp-writesite— a narrow wrapper script that only accepts{write|enable|disable|remove|archive|restore|remove-archive} <domain>orlog {access|error} <lines>, and only ever touches paths under/etc/nginx/sites-available/,/etc/nginx/sites-enabled/,/etc/nginx/sites-archived/, and the two fixed nginx log files. It re-validates the domain (and, forrestore/remove-archive, the archive filename) itself, independent of the Node-side validation./etc/sudoers.d/nginx-mcp— grants<user>passwordless sudo on exactlynginx -t,systemctl reload nginx,systemctl is-active --quiet nginx,certbot, and the wrapper above. Nothing broader. It also keepsAWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_DEFAULT_REGIONthrough sudo (which strips the environment by default) socertbot --dns-route53can see them forissue_wildcard_cert.
issue_wildcard_cert also needs the certbot-dns-route53 plugin —
npm run install:deps installs it for you (see Testing).
Why a wrapper script instead of sudo on tee/ln/rm
An earlier version granted sudo on generic file tools (tee, ln, rm)
so create_site could write into /etc/nginx/. That works, but it's a
wider trust boundary than the task needs: those commands can touch any
root-owned file on the box, not just nginx configs. If the MCP server
process were ever compromised or triggered unexpectedly, the blast radius
would be the whole filesystem.
The wrapper narrows that to one purpose-built binary that can only act on nginx site configs, one archive at a time, or tail one of two fixed log files — nothing else. The trade-off is one more artifact to deploy and keep in sync with the server, in exchange for sudo that can only ever do what this project needs.
Network requirements for certificate issuance
issue_cert and issue_wildcard_cert prove domain ownership two
different ways, with different requirements on where the box sits on your
network:
issue_cert(HTTP-01) — Let's Encrypt makes an inbound HTTP request to the domain on port 80. If you're behind a home/office router doing NAT, that request lands on whichever one private IP your port-forwarding rule targets. The machine running nginx (and this MCP server) has to be that exact machine — not just any box on your network, and not the Docker sandbox (a different private IP on the Docker bridge network). Calling it from the wrong box fails every time, since the challenge request never arrives.issue_wildcard_cert(DNS-01) — validates via a TXT recordcertbot-dns-route53creates in Route 53. This is outbound-only (the box calls the AWS API; nothing calls back in), so it has no port-forwarding requirement and works identically from any network, including the Docker sandbox.
Either way, DNS still has to point at your public IP (create_domain_record
handles that) — DNS and port-forwarding are two separate requirements, and
issue_cert needs both.
Environment variables
Variable | Used by | Notes |
|
| Credentials for a Route-53-scoped IAM user — no other AWS permissions needed |
|
| Find with |
| Same as above, plus | Optional — Route 53 is global, but the AWS SDK/boto3 still need a signing region; defaults to |
Testing
Four layers, from "needs almost nothing" to "exercises everything":
1. Dependencies — npm run install:deps
Debian/Ubuntu only, idempotent. Installs nginx, certbot,
python3-certbot-nginx, and python3-certbot-dns-route53 via apt if
missing; for anything already installed, it only reports whether the
version is current, since silently upgrading a package that might be
serving traffic isn't this script's call to make. If certbot looks like
a snap install (common — certbot's own docs recommend it over apt's
often-outdated package), it also tries installing certbot-dns-route53 as
a snap plugin, since an apt-installed plugin can be invisible to snap
certbot's isolated Python environment. That's best-effort and additive,
never a replacement for the apt package, so issue_wildcard_cert has a
working path either way. Also reports your Node version against the
>=20 that @aws-sdk/client-route-53 will eventually require.
2. Route 53 round trip — npm run test:dns
The only requirement is a working ROUTE53_HOSTED_ZONE_ID (+ AWS
credentials) in .env. It discovers your zone's own domain from the
hosted zone, creates a disposable CNAME under a random subdomain, verifies
it (directly against Route 53, and best-effort via public DNS), then
deletes it — cleanup runs even if a check in between fails, so a bad run
can't leave an orphaned record.
3. Docker sandbox — real nginx + certbot, disposable
cp .env.example .env # fill in AWS credentials + hosted zone ID
docker compose up -d --build
docker compose exec sandbox npm run inspectThe container runs systemd as PID 1, so sudo systemctl reload nginx and
friends work exactly as they do in production (needs --privileged and a
cgroup mount, which docker-compose.yml already sets up). nginx/
certbot/the plugins are installed via install-deps.sh, and the
wrapper/sudoers via setup.sh, both at image build time. Tear down with
docker compose down — nothing persists; every rebuild is a fresh install.
4. Automated tool-by-tool suite
cp .env.test.example .env.test # AWS credentials + a domain you control
npm run test:tools # against the Docker sandbox
npm run test:tools:host # against this machine directlyDrives every tool over the real stdio JSON-RPC protocol and prints
✓/✗/– per tool. .env.test is separate from .env — read on the host and
injected directly into each MCP server process the runner spawns, so the
two files never need to match. Before touching anything it verifies your
AWS credentials work and that TEST_DOMAIN is the zone's apex or a
subdomain of it. Everything then runs under a random
mcp-test-<random>.<TEST_DOMAIN> subdomain, self-cleans after each phase,
and does a final best-effort cleanup regardless of pass/fail. Certificate
issuance is opt-in — asked interactively, or pass --certs for a
non-interactive run — since it hits real Let's Encrypt staging and adds a
minute or two.
The two targets differ in exactly one way, issue_cert:
npm run test:tools(default) runs in the Docker sandbox, which isn't reachable from the internet, soissue_cert(HTTP-01) is always skipped — the cert scenario only exercisesissue_wildcard_cert(DNS-01) and the renew/revoke/delete chain built on it.npm run test:tools:hostrunsnode dist/index.jsdirectly on this machine. If this is the box your router actually forwards 80/443 to, the cert scenario testsissue_certtoo (waiting up to 300s for the disposable CNAME to propagate first), and the renew/revoke/delete chain runs against that cert instead. It refuses to start unless passwordless sudo already works for the current user — i.e.npm run setup -- <user>was run for the user actually invoking it, not some other account. Everything this touches is real production state, not a sandbox.
Connecting a client
MCP Inspector — the fastest feedback loop for poking at a tool directly:
npm run inspectPrints a URL with a session token. Run it against a real box, or the
Docker sandbox (docker compose exec sandbox npm run inspect).
Claude Desktop / claude.ai — add to your MCP client config:
{
"mcpServers": {
"nginx-certbot": {
"command": "node",
"args": ["/absolute/path/to/nginx-certbot-mcp/dist/index.js"]
}
}
}Or against the running Docker sandbox:
{
"mcpServers": {
"nginx-certbot-sandbox": {
"command": "docker",
"args": ["exec", "-i", "nginx-certbot-mcp-sandbox", "node", "dist/index.js"]
}
}
}Typical "add a new site" flow
create_domain_record— pointmysite.julcap.netatwww.julcap.net(wait for DNS propagation)
create_site— nginx serves the domain on port 80, reverse-proxied to the local service IP:portreload_nginxissue_cert— certbot validates via HTTP-01, updates nginx to redirect to 443
Contributing
Contributions are welcome. See CONTRIBUTING.md for guidelines.
License
nginx-certbot-mcp is source-available under the Elastic License 2.0. You may use, modify, and redistribute the software. However, you may not provide a substantial portion of its functionality to third parties as a hosted or managed service.
For commercial licensing or partnership enquiries, contact the maintainer.
Available Tools
23 toolscheck_cert_expiryARead-only
List every certbot-managed certificate on the box with its expiry date and days remaining, via certbot certificates. Read-only. Covers all certs certbot knows about, not just domains with an active nginx site.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| certificates | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already carry readOnlyHint=true and openWorldHint=false, and the description's 'Read-only' merely reinforces that rather than contradicting it. Beyond the annotation, it adds meaningful behavior: execution via `certbot certificates` and the coverage scope of all certs certbot knows about, including domains without an active nginx site. No annotation contradiction.
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?
Three short sentences with the core purpose front-loaded, followed by the mechanism and a scope qualifier. Every sentence earns its place, and the caveat about inactive nginx domains prevents a realistic mis-assumption.
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 zero-parameter read-only tool that has an output schema and a readOnlyHint annotation, the description is complete: it states what is listed, the mechanism, and the precise coverage boundary. Nothing an agent needs to call it correctly is missing.
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 takes zero parameters, so the empty schema needs no elaboration and the 0-param baseline of 4 applies. The description adds no parameter details, and none are required.
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 verb ('List'), resource ('certbot-managed certificates'), and the exact data returned (expiry date, days remaining), plus the underlying command. The read-only listing framing clearly distinguishes it from the cert-management siblings (issue_cert, renew_cert, revoke_cert, delete_cert) without needing to open a schema.
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 'List every certbot-managed certificate' phrasing plus 'Read-only' implies this is the inspection tool within the cert family, and the scope note ('not just domains with an active nginx site') sets a useful expectation. However, it never names a specific alternative or states an explicit when-to-use/when-not-to-use rule — sibling differentiation is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_dnsARead-only
Resolve a domain (CNAME first, then A/AAAA) against public resolvers (1.1.1.1, 8.8.8.8) rather than this box's own DNS, so the result matches what Let's Encrypt and the public internet see. Use before issue_cert / create_site to confirm a domain actually points where you expect. For confirming something is listening behind nginx, use check_upstream_health instead.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain to resolve, e.g. mysite.julcap.net |
Output Schema
| Name | Required | Description |
|---|---|---|
| values | No | Resolved values (IPs, or the CNAME target); only present when resolves is true |
| resolves | Yes | |
| record_type | No | Only present when resolves is true |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations provide readOnlyHint and openWorldHint, but the description adds behavioral nuance beyond that: it explains the resolution is against public resolvers to match Let's Encrypt's view, and mentions the query order. This is valuable context that isn't conveyed by annotations alone. No contradictions found.
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 (two sentences) and front-loaded with the core function and rationale. It avoids redundancy and each clause adds value—explaining the method, the use case, and the sibling alternative without 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 simple read-only tool with one parameter, an output schema (which we don't see but is indicated), and annotations covering safety, the description is complete. It covers why the public resolver is used, when to call it, and how it differs from a nearby sibling, leaving no gap an agent would need filled.
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?
There is only one parameter, 'domain', and the input schema already provides a clear description with an example. The tool description doesn't add extra parameter-level details beyond what the schema covers, so it earns the baseline score for high schema coverage.
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: resolving a domain against public resolvers (1.1.1.1, 8.8.8.8) with a specific query order (CNAME first, then A/AAAA). It explicitly names the sibling tool check_upstream_health as the alternative for a different task, making its purpose unambiguous.
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 explicitly states when to use the tool ('Use before issue_cert / create_site to confirm a domain actually points where you expect') and when not to ('For confirming something is listening behind nginx, use check_upstream_health instead'). This leaves no ambiguity about the tool's intended context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_upstream_healthARead-only
TCP-probe an upstream host:port to confirm something is actually listening there, independent of nginx or DNS. Use to sanity-check an upstream before create_site, or to debug a 502 afterward. For confirming a public domain resolves, use check_dns instead.
| Name | Required | Description | Default |
|---|---|---|---|
| timeout_ms | No | Milliseconds to wait before reporting unreachable | |
| upstream_host | Yes | Hostname or IP that nginx would proxy_pass to | |
| upstream_port | Yes | TCP port to probe |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | Human-readable outcome, e.g. success, timeout, or connection error detail |
| reachable | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds useful behavioral context beyond that: it is a TCP-level probe, independent of nginx or DNS, confirming that something is actually listening rather than relying on resolution.
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?
Three sentences with no filler: the first states what the tool does, the second gives concrete usage contexts, and the third routes to the relevant alternative. Every sentence earns its place and the key information is front-loaded.
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?
With a fully documented input schema, an output schema, and annotations covering read-only and open-world behavior, the description adds exactly what is missing: purpose, usage timing, and differentiation from check_dns. Nothing an agent needs to invoke it correctly is absent.
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 100%, so the parameters are already well-documented in the schema. The description does not need to elaborate on individual parameters; it correctly focuses on the tool's purpose and usage context.
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 uses a specific verb and resource: 'TCP-probe an upstream host:port to confirm something is actually listening there.' It also explicitly distinguishes itself from check_dns, making the tool's scope unmistakable even among many siblings.
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 gives concrete use cases: sanity-check an upstream before create_site or debug a 502 afterward. It also names the alternative tool (check_dns) and the condition that selects it, leaving no ambiguity about when to use this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_domain_recordAIdempotent
Upsert a Route 53 CNAME record pointing domain at target. Safe to call repeatedly - it's an upsert, not create-only. Run this before create_site / issue_cert and allow a few minutes for DNS propagation; issue_cert re-checks resolution itself, so it's safe to retry issue_cert if it reports the domain isn't resolving yet. For an ACME DNS-01 TXT challenge record, use create_txt_record instead.
| Name | Required | Description | Default |
|---|---|---|---|
| ttl | No | DNS TTL in seconds | |
| domain | Yes | The domain to create/update, e.g. mysite.julcap.net | |
| target | Yes | CNAME target the domain should point to, e.g. www.julcap.net |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | |
| success | Yes | |
| change_id | No | Route 53 change ID, useful for polling propagation status |
| change_status | No | Route 53 change status, e.g. PENDING or INSYNC |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although idempotentHint already signals repeatability, the description adds valuable behavioral context: DNS propagation may take minutes, issue_cert re-checks resolution itself, and retrying issue_cert is safe if the domain is not yet resolving. This goes beyond the annotations and helps the agent anticipate timing and failure behavior.
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 tight and front-loads the core purpose before providing workflow guidance. The sentence about repeatability overlaps with the idempotentHint annotation, which prevents a perfect score, but the remaining sentences all earn their 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 the rich schema, existing annotations, and presence of an output schema, the description fills the remaining practical gaps: where this tool fits in the provisioning flow, DNS propagation delays, retry safety, and which sibling tool to use instead. Nothing necessary for correct invocation is missing.
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 input schema documents all three parameters with descriptions and examples, so parameter semantics are fully covered by structured data. The description restates domain→target but adds no new constraints, syntax, or edge-case guidance beyond what the schema already provides.
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?
Clearly identifies the operation as an upsert of a Route 53 CNAME record pointing `domain` at `target`, which is specific and unambiguous. It also distinguishes itself from create_txt_record and from create-only semantics, so an agent can immediately tell what this tool does and does not do.
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?
Provides explicit sequencing ('Run this before create_site / issue_cert'), timing guidance ('allow a few minutes for DNS propagation'), and a clear alternative for TXT records ('use create_txt_record instead'). This gives the agent concrete conditions for when to invoke this tool versus a sibling.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_siteA
Create a new nginx server block from the websocket-capable default template. Validates and test-renders (nginx -t) before touching live config, and rolls back automatically if the test fails. Does NOT reload nginx or request a certificate - follow with reload_nginx to go live, then issue_cert to get SSL. To point an existing site at a different upstream later, use update_site instead of recreating it.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain for the new server block, e.g. mysite.julcap.net | |
| upstream_host | Yes | Hostname or IP nginx should proxy_pass to | |
| upstream_port | Yes | TCP port on the upstream host |
Output Schema
| Name | Required | Description |
|---|---|---|
| success | Yes | |
| config_path | No | Present on success: absolute path of the written config |
| test_output | Yes | Output of `nginx -t` against the rendered config |
| reload_required | Yes | True on success - nginx has not actually been reloaded yet |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the minimal annotations (openWorldHint and destructiveHint only), the description discloses key behavior: validation via `nginx -t`, automatic rollback on failure, and what it deliberately does not do (reload/cert). This fully informs the agent of side effects and prerequisites.
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?
Three sentences, no redundancy, and the most important facts (purpose, safety, follow-up) are front-loaded. Every sentence earns its place, making it efficient for an agent to parse.
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 moderate complexity and the presence of an output schema, the description covers all essential aspects: what it does, safety mechanism, required follow-up, and alternatives. Nothing an agent needs to call it correctly or decide whether to use it is missing.
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 covers 100% of parameters with clear descriptions, so the baseline is 3. The description adds context that the parameters define an nginx proxy upstream (host/port) and ties the domain to a server block, enriching meaning beyond the schema's mechanical definitions.
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 creates a new nginx server block using a specific template, distinguishing it from related tools like update_site. The verb 'create' and resource 'server block' are specific, and the mention of 'websocket-capable default template' adds precision.
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 explicitly provides usage context: does NOT reload nginx or request a certificate, and instructs to follow with reload_nginx and issue_cert. It also names the alternative (update_site) for existing sites, giving clear when-to-use vs. when-not-to guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_txt_recordAIdempotent
Upsert a Route 53 TXT record - e.g. for an ACME DNS-01 challenge (_acme-challenge., as used by issue_wildcard_cert) or domain verification. Quotes the value automatically if the caller didn't. Clean up afterward with delete_txt_record. For a CNAME pointing a domain at an upstream, use create_domain_record instead.
| Name | Required | Description | Default |
|---|---|---|---|
| ttl | No | DNS TTL in seconds | |
| value | Yes | TXT record value; wrapped in double quotes automatically if not already | |
| domain | Yes | Record name, e.g. _acme-challenge.mysite.julcap.net |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | |
| success | Yes | |
| change_id | No | Route 53 change ID, useful for polling propagation status |
| change_status | No | Route 53 change status, e.g. PENDING or INSYNC |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations (openWorldHint, idempotentHint, destructiveHint:false) already declare the safety profile; 'Upsert' is consistent with idempotentHint, so no contradiction. The description adds genuine behavioral value beyond annotations: automatic value quoting, the cleanup expectation, and the 'upsert' semantics. It doesn't mention auth needs or conflict behavior, but with annotations carrying the safety profile a 4 is fair.
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?
Four sentences with zero filler. The core purpose is front-loaded, followed by use case, cleanup instruction, and sibling differentiation. Every sentence earns its place and the most actionable constraint (auto-quoting) is embedded early.
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?
An output schema exists, so return values need no elaboration. Given the moderate complexity (3 params, 2 required), the description covers purpose, use cases, cleanup, and alternative routing. In a rich sibling context of 23 tools, the description fully disambiguates create_txt_record from create_domain_record and delete_txt_record.
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 100%, so all three params are already documented, setting the baseline at 3. The description adds meaningful value beyond the schema by explicitly stating the value auto-quoting behavior ('Quotes the value automatically if the caller didn't'), which maps directly to the value param, and reinforces the domain format with a concrete example.
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 verb and resource ('Upsert a Route 53 TXT record') plus concrete use cases (ACME DNS-01 challenge, domain verification) with a real example name (_acme-challenge.<domain>). It also names the specific sibling it relates to (issue_wildcard_cert) and the sibling it is not (create_domain_record), so an agent can differentiate without opening schemas.
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?
Gives explicit when-to-use context (DNS-01 challenge, domain verification), tells the agent to clean up afterward with delete_txt_record, and explicitly routes the CNAME case to create_domain_record instead. Alternatives and exclusions are both stated directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_certADestructiveIdempotent
Delete a certificate's files from certbot's local store. Destructive - requires confirm:true. Does not revoke the certificate first - if it may be compromised, call revoke_cert before this. Any nginx config still referencing the deleted files will fail to reload afterward.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | certbot cert name | |
| confirm | No | Must be true to actually delete; false (default) is a dry run |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructiveHint=true, so the safety baseline is covered. The description adds genuinely valuable context beyond that: the confirm:true gate, the critical ordering constraint (revoke must happen before delete), and the concrete consequence that nginx config referencing deleted files will fail to reload. This transforms a bare destructive flag into an actionable risk profile. No contradiction with annotations - destructiveHint matches 'Destructive', idempotentHint is consistent with deleting already-absent files being a harmless repeat, and openWorldHint=false matches a purely local operation.
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?
Three sentences, zero waste. The core purpose is front-loaded first, safety warnings follow in order of criticality: confirmation gate, revocation ordering, then downstream impact. Even the slight redundancy of 'Destructive' against destructiveHint is justified for a tool where a misfire is harmful. Every sentence 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?
For a destructive tool, this is complete. The description covers purpose, confirmation requirement, the revoke-before-delete decision, and post-delete consequences. The output schema exists so return values need no description, and the strong annotations carry idempotency and destructiveness. An agent has everything needed to decide whether and how to call this tool safely.
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 100%, so the schema already documents both domain ('certbot cert name') and confirm ('Must be true to actually delete; false (default) is a dry run'). The description restates the confirm requirement but adds no new parameter-level meaning beyond the schema. Baseline 3 is correct when the schema carries the full parameter documentation burden.
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 verb and resource: 'Delete a certificate's files from certbot's local store.' It clearly differentiates from the sibling revoke_cert by explicitly stating deletion is not revocation, which is exactly the ambiguity this tool family needs resolved. An agent can distinguish delete_cert from revoke_cert without opening either schema.
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 gives explicit routing guidance: 'if it may be compromised, call revoke_cert before this' names the alternative and the condition that selects it. It also warns about the downstream failure mode (nginx reload failures) which implicitly tells the agent to confirm no config references the cert before deleting. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_domain_recordADestructiveIdempotent
Delete the Route 53 CNAME record for a domain. Destructive - requires confirm:true to actually act; without it, returns what would happen and changes nothing. Looks up the exact existing record first rather than guessing its TTL/value.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | The domain whose CNAME record should be deleted | |
| confirm | No | Must be true to actually delete; false (default) is a dry run |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | |
| success | Yes | |
| change_id | No | Route 53 change ID, useful for polling propagation status |
| change_status | No | Route 53 change status, e.g. PENDING or INSYNC |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Explicitly discloses the destructive nature and the confirm:true safety gate, including the dry-run behavior. Adds the lookup-first behavior, which goes beyond the annotations and helps predict side effects.
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, front-loaded with the main action, and each sentence adds a distinct piece of information without waste.
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 two-parameter destructive tool, the description plus annotations and output schema cover safety, dry-run, and lookup behavior. Nothing essential is missing.
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 reinforces the confirm parameter's role and explains why no TTL/value parameters exist by noting the tool looks up the existing record. Schema coverage is 100%, so the baseline is 3, but this added context earns a slight upgrade.
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 verb and resource: delete the Route 53 CNAME record for a domain. Differentiates from sibling tools like delete_txt_record and delete_cert by specifying the record type and service.
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?
Clearly implies when to use it: to remove a CNAME record from Route 53. Does not explicitly name alternatives or exclusions, but the domain/CNAME scope provides sufficient context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_siteADestructiveIdempotent
Disable, archive, and delete the nginx server block for a domain. Destructive - requires confirm:true to actually act; without it, returns what would happen. Does not touch any certbot certificate for the domain. Does NOT reload nginx - call reload_nginx afterward. The archived copy can be brought back with restore_site.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain whose server block should be removed | |
| confirm | No | Must be true to actually act; false (default) is a dry run |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | |
| success | Yes | |
| reload_required | Yes | True on success - nginx has not actually been reloaded yet |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and idempotentHint=true, but the description goes well beyond them by disclosing the dry-run mode, the fact that certificates are left alone, that nginx is not reloaded, and that an archived copy can be restored. These are critical behavioral traits not inferable from the annotations alone.
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?
Four sentences, each carrying distinct information: what happens, the confirmation guard, the certificate non-effect, and the nginx reload/restore caveats. It is slightly dense but well-organized and front-loaded with the core action.
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 destructive tool with an output schema, full parameter schema coverage, and rich annotations, the description covers all necessary operational context: how to actually trigger deletion, what is not affected, what to do after, and how to undo. No important gap remains.
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 100%, with both parameters fully described in the JSON schema itself. The description reinforces the confirm parameter's dry-run semantics but adds no new meaning beyond what the schema already documents, so the baseline of 3 applies.
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 names a specific verb ('delete'), a specific resource ('nginx server block for a domain'), and ties in the related actions 'disable' and 'archive'. It clearly differentiates this from sibling tools like delete_cert and revoke_cert by scoping to the nginx server block only.
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?
Explicitly states the confirm:true requirement and the dry-run behavior without it, explains that certbot certificates are untouched, says nginx is NOT reloaded and directs the agent to call reload_nginx afterward, and mentions restore_site as the reversal path. This fully routes the agent to the correct workflow.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_txt_recordADestructiveIdempotent
Delete the Route 53 TXT record for a domain - e.g. to clean up an ACME DNS-01 challenge record left behind by create_txt_record or issue_wildcard_cert. Destructive - requires confirm:true to actually act; without it, returns what would happen and changes nothing. Looks up the exact existing record first rather than guessing its TTL/value. For a CNAME record, use delete_domain_record instead.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Record name whose TXT record should be deleted, e.g. _acme-challenge.mysite.julcap.net | |
| confirm | No | Must be true to actually delete; false (default) is a dry run |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | |
| success | Yes | |
| change_id | No | Route 53 change ID, useful for polling propagation status |
| change_status | No | Route 53 change status, e.g. PENDING or INSYNC |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although destructiveHint is already true, the description adds meaningful detail: it requires confirm:true to act, otherwise it is a dry run that changes nothing. It also discloses that the tool looks up the exact existing record first rather than guessing TTL/value, which is important behavioral context beyond the annotations. No contradiction with annotations is present.
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 four sentences with each one serving a distinct purpose: purpose/example, destructive behavior/confirm requirement, lookup behavior, and sibling alternative. It is front-loaded with the most important information and contains no filler or repetition.
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 moderate complexity, the description covers purpose, usage triggers, destructive behavior, confirmation requirement, and alternative tool routing. The output schema exists, so return value details are not needed in the description. An agent has enough information to decide when to use this tool and how to invoke it safely.
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 100%, so the schema already documents both domain and confirm. The description reinforces the confirm parameter's dry-run behavior and adds the 'looks up the exact existing record' detail, but this is more about tool behavior than new parameter-level meaning. It meets the baseline but does not add substantial semantic value beyond the schema.
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 opens with a specific verb and resource: 'Delete the Route 53 TXT record for a domain.' It also gives a concrete use case (cleaning up an ACME DNS-01 challenge record) and explicitly differentiates itself from delete_domain_record for CNAME records. An agent can immediately understand what this tool does and how it differs from siblings.
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 explicitly states when to use this tool: to clean up TXT records left by create_txt_record or issue_wildcard_cert. It also provides an explicit alternative: 'For a CNAME record, use delete_domain_record instead.' This gives clear context and exclusion criteria, leaving little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_nginx_statusARead-only
Report whether the nginx service is active (via systemctl) and its version string. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| running | Yes | |
| version | Yes | `nginx -v` output, or an explanatory message if it couldn't be determined |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The read-only nature is disclosed both in the description and the readOnlyHint annotation, with no contradiction. The description adds value beyond the annotation by specifying the systemctl mechanism and the version-string output, which are not present in the annotation. No hidden side effects are omitted.
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 two short sentences with no wasted words. The core behavior is front-loaded, and the 'Read-only' note reinforces safety 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?
For a no-parameter, read-only status tool with a defined output schema and annotations, the description is sufficient. It states the check performed, the mechanism, and the extra version output. There is no missing context that an agent would need to invoke it correctly.
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 zero parameters, and the schema description coverage is 100% (empty schema). The description does not need to explain parameter meaning because there are none, so the zero-parameter baseline of 4 applies.
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 verb ('report'), a specific resource (nginx service), and the exact output (active status and version string). It clearly distinguishes itself from mutation siblings like reload_nginx by framing this as a status query.
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 when you need to know whether nginx is active or its version, but it does not explicitly mention alternatives or situations where this tool should not be used. No exclusion criteria or sibling routing is provided, so the guidance is only implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_site_configARead-only
Get the raw, unparsed nginx config file for one domain from sites-available. Throws if no config exists for that domain - call list_sites first if you're not sure it exists.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain as it appears in sites-available, e.g. mysite.julcap.net |
Output Schema
| Name | Required | Description |
|---|---|---|
| domain | Yes | |
| raw_config | Yes | Full contents of the nginx config file, verbatim |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the read-only nature is covered. The description adds valuable behavior beyond annotations: it discloses the throw condition when the config is missing, and clarifies the output format as 'raw, unparsed' (implying no processing or validation). This goes beyond the annotations and provides actionable context for the agent.
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 two sentences with zero waste. The core action and resource are front-loaded in the first sentence, and the usage guidance (throw condition and alternative) appears in the second. 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?
The tool is simple with a single parameter, and the description covers the error condition and provides a fallback path. An output schema exists (though not shown), and annotations handle the read-only safety. Nothing an agent needs to call this correctly is missing.
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 input schema already provides a clear description for the single 'domain' parameter ('Domain as it appears in sites-available, e.g. mysite.julcap.net') with 100% coverage. The tool description adds only the phrase 'for one domain,' which adds no new meaning beyond the schema. Baseline of 3 is appropriate since the schema does the heavy lifting.
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 verb and resource: 'Get the raw, unparsed nginx config file for one domain from sites-available.' It clearly distinguishes this from sibling tools like list_sites (which lists domains) and check_cert_expiry (which checks certificates). The scope is explicit — one domain, from sites-available — leaving no ambiguity about the tool's function.
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 explicitly tells the agent when to use it and when not to: 'Throws if no config exists for that domain - call list_sites first if you're not sure it exists.' This names the alternative (list_sites) and the condition that selects it, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
issue_certA
Request a certificate via certbot --nginx (HTTP-01 validation). Requires an nginx server block for domain to already exist (create_site) - certbot's nginx plugin edits that existing sites-available config in place, adding an SSL server block and an HTTP->HTTPS redirect; it does not create a new site from scratch, and it reloads nginx itself on success (no separate reload_nginx call needed). Pre-checks that the domain resolves and fails fast with guidance if not, avoiding a wasted attempt against Let's Encrypt's rate limits. Defaults to Let's Encrypt staging, which issues browser-untrusted certs but is exempt from rate limits - pass staging:false only when you're ready for a real, publicly CT-logged certificate: production Let's Encrypt enforces real per-domain issuance rate limits (a handful of certs per week), and a mis-issued cert isn't silently undone - call revoke_cert if you need to invalidate one. For a *.domain wildcard, use issue_wildcard_cert instead - HTTP-01 can't validate wildcards.
| Name | Required | Description | Default |
|---|---|---|---|
| No | Contact email registered with the Let's Encrypt account, used for renewal-failure and expiry notices. Omitted registers with --register-unsafely-without-email, so Let's Encrypt cannot warn you if a future automated renewal fails. | ||
| domain | Yes | Domain to request a certificate for. Must already resolve (see check_dns) and already have an nginx server block from create_site - certbot edits that existing config rather than creating one. | |
| staging | No | True (default) uses Let's Encrypt's staging CA - browser-untrusted certs, but exempt from production rate limits; use for testing the flow. False requests a real, browser-trusted cert and counts against production rate limits. |
Output Schema
| Name | Required | Description |
|---|---|---|
| success | Yes | |
| dns_check | No | Present only when the DNS pre-check failed, before certbot was even invoked |
| certbot_output | Yes | Raw combined stdout/stderr from the certbot CLI invocation, on success or failure |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations provide openWorldHint=true and destructiveHint=false, but the description goes far beyond that. It discloses that the tool edits existing config, reloads nginx, pre-checks domain resolution and fails fast, defaults to staging (which issues untrusted certs but avoids rate limits), and warns that production issuance has real rate limits and that revoke_cert is needed to invalidate a mis-issued cert. This is rich behavioral context not available in annotations or 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?
Although the description is a single long paragraph, it is tightly packed with actionable information. It front-loads the core action, then covers prerequisites, behavioral notes, staging nuance, and the wildcard alternative. There is no redundancy or filler; every sentence adds value and the flow is logical.
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 a mutation with external dependencies (Let's Encrypt) and rate-limit considerations. The description covers prerequisites (existing server block), behavior (edits config, reloads nginx), staging vs production, rate limits, revocation fallback, and wildcard routing. An agent has everything it needs to decide whether and how to call this tool correctly. The output schema exists, so return-value details are not required.
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 100%, so baseline is 3, but the description adds substantial meaning beyond the schema. For email, it explains the consequence of omission (no renewal warnings). For domain, it reiterates the prerequisite of an existing server block and points to check_dns. For staging, it elaborates on the trade-offs between staging and production, including rate limits and CT-logging. The description genuinely enhances parameter understanding.
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 opens with a specific verb and resource: 'Request a certificate via `certbot --nginx` (HTTP-01 validation).' It clearly states what the tool does and distinguishes it from the sibling issue_wildcard_cert, which is explicitly named for wildcard domains. The purpose is unambiguous and differentiated.
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 explicitly states when to use this tool: it requires an existing nginx server block from create_site, and it notes that certbot edits that config in place and reloads nginx itself, so no separate reload_nginx call is needed. It also names the alternative for wildcards (issue_wildcard_cert) and explains why HTTP-01 can't validate wildcards, providing clear exclusion criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
issue_wildcard_certA
Request a wildcard certificate (domain and *.domain) via certbot --dns-route53 (DNS-01 validation, required since HTTP-01 can't prove ownership of a wildcard). Requires the certbot-dns-route53 plugin installed on the box and AWS credentials in the environment (see README) - fails fast with guidance if credentials are missing. Defaults to staging. For a single non-wildcard domain, use issue_cert instead.
| Name | Required | Description | Default |
|---|---|---|---|
| No | Contact email for the Let's Encrypt account; omitted registers unsafely-without-email | ||
| domain | Yes | Base domain, e.g. julcap.net - issues it plus *.julcap.net | |
| staging | No | True (default) uses Let's Encrypt's staging CA: untrusted certs, but no rate-limit risk |
Output Schema
| Name | Required | Description |
|---|---|---|
| success | Yes | |
| certbot_output | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark openWorldHint=true and destructiveHint=false. The description adds useful behavior: it fails fast with guidance on missing credentials, defaults to staging, and explains why DNS-01 is required. It could be slightly stronger by stating whether temporary Route53 DNS records are created during validation.
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?
Three dense sentences: first states the core operation and constraint, second covers prerequisites and failure behavior, third covers default and alternative. No filler or repetition of schema details.
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 one required parameter, full param descriptions, an output schema, and an open-world annotation, the description covers the critical operational facts: wildcard scope, DNS-01 requirement, plugin/credential prerequisites, default staging, and the sibling alternative. Nothing essential is missing.
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 100%, so the baseline applies; the description adds no new parameter-level meaning beyond what the schema's `domain`, `staging`, and `email` descriptions already say. It does reinforce the wildcard scope and staging default, but does not compensate for anything missing.
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 action ('Request a wildcard certificate'), includes exact scope (`domain` and `*.domain`), and names the sibling to avoid (`issue_cert` for single non-wildcard domains). This makes it distinguishable from the related certificate tools without opening the schema.
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 explicitly says when to use this tool (wildcard certs needing DNS-01) and when not to ('For a single non-wildcard domain, use issue_cert instead'). It also states the prerequisites (certbot-dns-route53 plugin, AWS credentials), which is actionable usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_archived_sitesARead-only
List archived nginx configs created by delete_site, newest first. Feed a filename from here into restore_site's archive_filename to restore a specific archive instead of the newest.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | Filter to one domain's archives |
Output Schema
| Name | Required | Description |
|---|---|---|
| archives | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=truecars, and the description adds useful behavioral context beyond that: these archives are created by delete_site, are sorted newest first, and their filenames are directly consumable by restore_site. It does not contradict the annotations.
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 efficient sentences front-load the core purpose and ordering, then immediately explain the downstream integration with restore_site. There is no filler or repetition of schema 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?
With an output schema, a single well-documented optional parameter, and read-only annotations, the description covers everything an agent needs: what to list, the order, and how the result is used by restore_site. Nothing critical is missing.
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 description covers the single optional domain parameter at 100%, so the baseline applies. The description does not add details about the domain filter, but it doesn't need to because the schema already documents it clearly.
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 uses a specific verb ('List'), names the exact resource ('archived nginx configs'), and clarifies the origin ('created by delete_site'). It also gives ordering ('newest first'), which distinguishes it from the sibling list_sites and makes the tool's role obvious.
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 clearly connects this tool to restore_site: filenames from this output feed into restore_site's archive_filename to restore a specific archive. It strongly implies when to use this tool over list_sites, though it does not explicitly state a negative condition like 'use list_sites for active sites.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_sitesARead-only
List every nginx server block currently in sites-enabled, with domain, upstream, and whether SSL looks configured. Read-only - parses config files directly, does not shell out to nginx. Use get_site_config for one domain's full raw config.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| sites | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description adds useful behavioral detail beyond that: it parses config files directly and does not shell out to nginx. This clarifies how the read-only operation is performed and implies a lightweight, direct inspection.
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 two sentences, front-loaded with the core function and scope, then the read-only behavior, then the sibling alternative. Every sentence adds distinct value with no 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?
For a parameterless read-only list tool with an output schema and strong annotations, the description fully covers purpose, scope, behavior, and the relevant sibling tool. Nothing an agent needs to invoke it correctly is missing.
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 zero parameters, so the baseline is 4. The description adds no parameter syntax, but that is unnecessary here; the empty schema and zero-parameter context fully describe invocation requirements.
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 names a specific verb ('List'), a specific resource ('nginx server block'), and a precise scope ('sites-enabled'). It also lists the returned aspects (domain, upstream, SSL configuration), making the tool's function unambiguous.
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 explicitly provides a usage alternative: 'Use get_site_config for one domain's full raw config.' This tells an agent when to prefer this tool versus a sibling, leaving no ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
prune_archivesADestructiveIdempotent
Delete archived site configs (from delete_site) older than a threshold. Destructive - requires confirm:true to actually act; without it, lists what would be deleted and changes nothing. Continues past individual failures and reports how many actually got removed.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | No | Must be true to actually delete; false (default) is a dry run | |
| older_than_days | No | Age threshold in days |
Output Schema
| Name | Required | Description |
|---|---|---|
| pruned | Yes | Archive filenames removed - or, when confirm is false, that would be removed |
| message | Yes | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark destructiveHint=true and idempotentHint=true, but the description adds essential behavioral detail: the default is a dry run, deletion requires explicit confirmation, it continues past individual failures, and it reports the actual removal count. These are important safety and execution traits not visible from annotations alone.
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?
Three sentences, each carrying critical information: the core action, the safety mechanism, and the failure/reporting behavior. It is front-loaded with the main purpose and wastes no words.
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 destructive nature, the description covers the necessary safety context (dry run, confirm requirement), behavior on partial failure, and output reporting. Combined with full parameter schema coverage and an output schema, nothing essential is missing for correct invocation.
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 100%, so both parameters are already documented. The description's 'older than a threshold' matches older_than_days and 'requires confirm:true' matches confirm, but it adds little beyond what the schema already states. Baseline 3 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 states a specific verb ('Delete'), a specific resource ('archived site configs (from delete_site)'), and a precise scope ('older than a threshold'). It clearly distinguishes this tool from siblings like list_archived_sites and delete_site by tying it to archived configs and threshold-based pruning.
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 clearly explains how to use the tool: confirm:true triggers deletion, while default is a dry-run that lists and changes nothing. It implies when to use it (for bulk pruning of old archived configs) but does not explicitly name alternatives or state when not to use it, leaving slight room for inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reload_nginxAIdempotent
Run nginx -t and reload the live service only if the config test passes - never reloads a broken config. Call this after create_site, delete_site, or restore_site to apply the change; those tools do not reload automatically.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| success | Yes | |
| test_output | Yes | Combined stdout/stderr of `nginx -t` |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as idempotent, non-destructive, and closed-world. The description adds useful behavioral context: it runs a config test first and only reloads if that passes this is not stated in the annotations. It does not describe response/exit behavior, but the output schema likely covers that, so this is a strong contribution.
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 two concise sentences. The first front-loads the core behavior and safety guard, and the second provides the exact invocation context. Every sentence earns its place with no filler or redundant restatement.
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 zero-parameter tool with an output schema and annotations covering idempotency and destructiveness, the description is complete. It tells the agent what the tool does, when to call it, why it is needed, and what safety mechanism it uses. Nothing essential is missing.
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 zero parametersasi the schema confirms, and schema description coverage is 100%. Per the rubric, a zero-parameter tool gets a baseline of 4. The description does not need to explain parameters, and it does not attempt to invent any.
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 precise action: run `nginx -t` and reload the live service only if the config test passes. It clearly identifies the resource (nginx), the specific behavior (guarded reload), and the context that distinguishes it from sibling tools that modify site configs but do not reload.
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 explicitly says when to use the tool: after create_site, delete_site, or restore_site. It also clarifies that those tools do not reload automatically, which removes ambiguity about whether this step is needed. It also implies a key constraint: never reloads a broken config.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
renew_certA
Run certbot renew, optionally scoped to one cert via --cert-name. Defaults to --dry-run (simulates against Let's Encrypt staging without touching the live cert or rate limit) - pass dry_run:false only when you mean to actually renew. Always disables certbot's random pre-renewal sleep so the call returns synchronously.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | Cert name to renew; omit to renew everything due | |
| dry_run | No | True (default) simulates the renewal without touching the live cert |
Output Schema
| Name | Required | Description |
|---|---|---|
| success | Yes | |
| certbot_output | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
It discloses non-obvious behaviors: the staging simulation for dry-run, no rate-limit impact, permanent disarming of certbot's pre-renewal sleep, and synchronous return. These details are valuable beyond the sparse annotations (only `openWorldHint: true`, `destructiveHint: false`) and do not contradict them.
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 and front-loaded: the first sentence states the core command and scoping, the second covers the default and its safety cue, and the third explains the synchronous return. Every sentence carries essential information with no 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?
For a two-parameter tool with a full output schema and straightforward behavior, this description covers the default state, the risky escape hatch, scoping, and execution behavior. Nothing needed for correct invocation is missing.
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 complete (100%), and the description adds the critical meaning of `dry_run: false` as a deliberate real renewal rather than simulation. It also clarifies that the `domain` parameter is actually a cert-name scope, which is not explicitly stated in the schema.
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 runs `certbot renew`, scopes to a single cert name via `--cert-name`, and defaults to `--dry-run`. It is distinct from the sibling issue/revoke/delete certificate tools, so an agent can tell when to invoke it.
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 gives clear guidance on when to keep the default dry-run and when to pass `dry_run: false` ('only when you mean to actually renew'). It does not explicitly contrast with issue_cert/revoke_cert for choosing a renewal path, but the conditions for using the tool safely are well specified.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
restore_siteADestructive
Restore a domain's nginx config from its most recent archive (created by delete_site) and enable it. Destructive to any current config for that domain - requires confirm:true. Test-renders before enabling and rolls back automatically if that fails. Does NOT reload nginx - call reload_nginx afterward.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain to restore | |
| confirm | No | Must be true to actually act; false (default) is a dry run | |
| archive_filename | No | A filename from list_archived_sites; defaults to the newest archive for this domain |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | |
| success | Yes | |
| reload_required | Yes | True on success - nginx has not actually been reloaded yet |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds crucial behavior beyond the annotations: it is destructive to current config, requires confirmation, test-renders before enabling, rolls back automatically on failure, and does not reload nginx. These details complement the destructiveHint:true annotation and do not contradict it.
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?
Four short sentences, each with a distinct role: purpose, destructive guard, failure mitigation, and the reload follow-up. Information is front-loaded and there is no 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?
Given the destructiveHint annotation and the presence of an output schema, the description covers everything an agent needs: what is restored, the safety mechanism, the confirmation gate, and the necessary next-step reload. There are no hidden gaps.
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 100%, so the parameters are already well-documented (including the confirm default/dry-run and archive_filename default). The description restates the confirm requirement but does not add new parameter-level information, so the baseline 3 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?
States a specific verb ('restore'), a precise resource ('domain's nginx config'), the source ('most recent archive created by delete_site'), and the outcome ('enable it'). This clearly positions the tool as the inverse of delete_site and distinguishes it from create_site and reload_nginx.
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 states the mandatory confirm:true requirement, notes that confirm:false is a dry run, and explicitly instructs the agent to call reload_nginx afterward because this tool does not reload nginx. This is actionable usage guidance with a clear boundary.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
revoke_certADestructive
Revoke a certificate with Let's Encrypt (e.g. after a key compromise) - the CA distrusts it immediately, browser-wide, for any site still serving it. Destructive and effectively irreversible - requires confirm:true. Leaves the cert files on disk; follow with delete_cert to remove them.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | certbot cert name | |
| confirm | No | Must be true to actually revoke; false (default) is a dry run |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Although destructiveHint=true already flags mutation, the description adds substantial behavioral specifics: immediate browser-wide distrust, effective irreversibility, the confirm:true requirement, and the fact that cert files are left on disk. This goes well beyond the annotation and prepares the agent for real consequences.
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?
Three tightly packed sentences: purpose and trigger, consequence and safety requirement, and post-condition with follow-up. Every sentence earns its place with no 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 has an output schema, 100% parameter coverage, and annotations. The description adds the missing real-world behavior, irreversibility, and next-step guidance, so an agent has everything needed to call it correctly.
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 100% and already explains both parameters: domain as a certbot cert name and confirm as a guard with false default. The description reinforces the confirm requirement but does not add meaning beyond the schema. A baseline of 3 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 states a specific verb ('Revoke') and resource ('a certificate with Let's Encrypt'), then clarifies its immediate consequence. It clearly distinguishes itself from the sibling delete_cert by noting the files remain on disk, and from issue/renew by its destructive nature.
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 gives a concrete trigger ('after a key compromise'), warns that it is destructive and irreversible, and directs the user to follow with delete_cert for file removal. It does not explicitly enumerate when not to use it, but the destructive warning and follow-up relationship provide solid usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tail_site_logsARead-only
Tail nginx's access or error log (capped at 1000 lines). domain is a best-effort substring filter, not a true per-vhost filter - see the result's note.
| Name | Required | Description | Default |
|---|---|---|---|
| lines | No | Most recent lines to return, capped at 1000 | |
| domain | No | Best-effort substring filter over each log line - see the result's `note` for its limits | |
| log_type | Yes | Which nginx log to read |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Present when a domain filter was applied, or when the read failed |
| lines | Yes | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the operation as read-only, and the description adds useful behavioral facts beyond that: the 1000-line cap and the best-effort substring filtering limitation with a pointer to the note in the result. It does not need to restate read safety.
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 compact sentences front-load the core purpose and cap, then deliver the key caveat about domain filtering. No filler or redundant clauses.
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 three-parameter, read-only log-tail tool with an output schema present, the description covers the essential behavioral constraints (line cap, domain caveat, result note). Additional details would be redundant with the schema and output schema.
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 100% and the prose largely mirrors the schema (e.g., 'capped at 1000' appears in both). The description adds no new parameter-level detail beyond what the schema already provides, so the baseline 3 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 states a specific action ('Tail') on a specific resource ('nginx's access or error log') with an important bound ('capped at 1000 lines'). This clearly distinguishes it from all siblings, none of which read logs.
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?
There are no sibling log-reading tools to contrast with, but the description gives clear context for invoking the tool and explicitly warns that the domain parameter is not a true per-vhost filter. It stops short of an explicit when-to-use/when-not-to-use statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_siteAIdempotent
Update an existing site's upstream by rewriting its proxy_pass directive(s) in place - everything else in the config, including any SSL server block issue_cert/certbot added, is left untouched. Fails if the domain has no existing config (use create_site instead) or has no proxy_pass directive to update. Test-renders before keeping the change and rolls back automatically if nginx -t fails. Does NOT reload nginx - call reload_nginx afterward.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain of the existing site to update | |
| upstream_host | Yes | New hostname or IP nginx should proxy_pass to | |
| upstream_port | Yes | New TCP port on the upstream host |
Output Schema
| Name | Required | Description |
|---|---|---|
| success | Yes | |
| test_output | Yes | Output of `nginx -t` against the rewritten config, or an explanatory message if nothing was changed |
| reload_required | Yes | True on success - nginx has not actually been reloaded yet |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (idempotent, non-destructive), the description reveals critical behavioral traits: it rewrites proxy_pass in place, preserves SSL config, test-renders before committing, and auto-rolls back on nginx -t failure. It also discloses the lack of reload. These details significantly exceed what annotations alone convey.
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 efficient and front-loaded with the core action and key constraints. Every sentence carries essential information (scope, failure conditions, safety mechanism, post-requisite), with zero fluff or repetition.
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 description covers failure conditions, the test-render/rollback mechanism, the reload requirement, and what is left untouched. With an output schema present and annotations providing safety hints, an agent has everything needed to invoke this tool correctly and predict its outcomes.
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 100%, so each parameter is already documented. The description adds value by linking the parameters to the operation (domain identifies the existing site, upstream_host/port become the new proxy_pass target), reinforcing their roles. This extra context elevates it above the baseline 3.
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 verb 'Update', the resource 'existing site's upstream' via proxy_pass rewriting, and explicitly differentiates from create_site and reload_nginx. It specifies exactly what is modified and what remains untouched, leaving no ambiguity about the tool's purpose.
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 explicitly states when to use this tool (existing site with proxy_pass) and when not to (if no existing config, use create_site instead; does not reload, call reload_nginx afterward). It names the alternatives directly, providing unambiguous routing for an agent.
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.
24 tool updates
v0.1.1- Changed
check_cert_expiry1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "certificates": { + "items": { + "additionalProperties": false, + "properties": { + "auto_renew_enabled": { + "type": "boolean" + }, + "days_remaining": { + "description": "Negative if the certificate has already expired", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" + }, + "domain": { + "type": "string" + }, + "expires_at": { + "description": "Expiry date/time as reported by certbot", + "type": "string" + } + }, + "required": [ + "domain", + "expires_at", + "days_remaining", + "auto_renew_enabled" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "certificates" + ], + "type": "object" +}
- Added
check_dns - Added
check_upstream_health - Added
create_domain_record - Removed
create_server_block - Added
create_site - Added
create_txt_record - Added
delete_cert - Added
delete_domain_record - Added
delete_site - Added
delete_txt_record - Added
get_nginx_status - Changed
get_site_config3 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - changed
Input schema / properties / domain / descriptionPrevious value: -"The domain to look up, e.g. my.domain.com"New value: +"Domain as it appears in sites-available, e.g. mysite.julcap.net" - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "domain": { + "type": "string" + }, + "raw_config": { + "description": "Full contents of the nginx config file, verbatim", + "type": "string" + } + }, + "required": [ + "domain", + "raw_config" + ], + "type": "object" +}
- Changed
issue_cert5 fields changed- removed
Input schema / additionalPropertiesRemoved value: -false - added
Input schema / properties / domain / descriptionAdded value: +"Domain to request a certificate for. Must already resolve (see check_dns) and already have an nginx server block from create_site - certbot edits that existing config rather than creating one." - added
Input schema / properties / email / descriptionAdded value: +"Contact email registered with the Let's Encrypt account, used for renewal-failure and expiry notices. Omitted registers with --register-unsafely-without-email, so Let's Encrypt cannot warn you if a future automated renewal fails." - added
Input schema / properties / staging / descriptionAdded value: +"True (default) uses Let's Encrypt's staging CA - browser-untrusted certs, but exempt from production rate limits; use for testing the flow. False requests a real, browser-trusted cert and counts against production rate limits." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "certbot_output": { + "description": "Raw combined stdout/stderr from the certbot CLI invocation, on success or failure", + "type": "string" + }, + "dns_check": { + "additionalProperties": false, + "description": "Present only when the DNS pre-check failed, before certbot was even invoked", + "properties": { + "record_type": { + "description": "Only present when resolves is true", + "enum": [ + "A", + "AAAA", + "CNAME" + ], + "type": "string" + }, + "resolves": { + "type": "boolean" + }, + "values": { + "description": "Resolved values (IPs, or the CNAME target); only present when resolves is true", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "resolves" + ], + "type": "object" + }, + "success": { + "type": "boolean" + } + }, + "required": [ + "success", + "certbot_output" + ], + "type": "object" +}
- Added
issue_wildcard_cert - Added
list_archived_sites - Changed
list_sites1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "sites": { + "items": { + "additionalProperties": false, + "properties": { + "config_path": { + "description": "Absolute path to the enabled config file", + "type": "string" + }, + "domain": { + "description": "server_name parsed from the config, or the filename if not found", + "type": "string" + }, + "ssl_enabled": { + "description": "True if the config listens on 443 ssl or sets ssl_certificate", + "type": "boolean" + }, + "upstream": { + "description": "proxy_pass target, or null if none was found", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "domain", + "config_path", + "upstream", + "ssl_enabled" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "sites" + ], + "type": "object" +}
- Added
prune_archives - Changed
reload_nginx1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "success": { + "type": "boolean" + }, + "test_output": { + "description": "Combined stdout/stderr of `nginx -t`", + "type": "string" + } + }, + "required": [ + "success", + "test_output" + ], + "type": "object" +}
- Added
renew_cert - Added
restore_site - Added
revoke_cert - Added
tail_site_logs - Added
update_site
6 tool updates
v0.1.0- First observed
check_cert_expiry - First observed
create_server_block - First observed
get_site_config - First observed
issue_cert - First observed
list_sites - First observed
reload_nginx
TDQS
Scored across 23 tools
Every tool targets a distinct resource and action: nginx site inspection vs. mutation, cert issuance vs. renewal vs. revocation, and DNS record types are cleanly separated. Cross-references like check_dns vs. check_upstream_health and create_domain_record vs. create_txt_record eliminate ambiguity.
All tools follow a consistent snake_case verb_noun pattern with predictable verbs: list, get, check, create, delete, update, restore, reload, issue, renew, revoke. There are no mixed conventions or vague generic names.
At 23 tools, this is on the heavy end of the scale, though the count is justified by spanning three related areas: nginx site lifecycle, certbot certificate lifecycle, and Route 53 DNS record management. Each tool has a real purpose, but the overall surface area feels larger than a typical focused server.
The tool surface covers the full lifecycle for nginx sites, certificates, and DNS records: create/read/update/delete/restore for sites, issue/renew/revoke/delete for certs, and upsert/delete for records. Minor gaps exist, such as update_site only rewriting proxy_pass directives rather than supporting arbitrary config edits, but most workflows can be completed without dead ends.
Maintenance
Related MCP Connectors
Manage websites, help documents and customer-support conversations with safe, scoped tools.
Provides capabilities that let LLM agents perform a range of infrastructure management tasks.
Read-only MCP access to a documented IT fleet: state, changes, posture. 15 tools.
Deploy and manage applications, databases, domains, and git repos
Related MCP Servers
- AlicenseBqualityCmaintenanceEnables management of Nginx Proxy Manager instances for configuring proxy hosts, requesting Let's Encrypt SSL certificates, and managing access lists. It allows users to control their web proxy infrastructure through natural language commands in MCP-compatible environments.503MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to manage Nginx Proxy Manager instances through natural language, covering 28 tools for proxy hosts, certificates, streams, and more.MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to manage Nginx Proxy Manager, including proxy hosts, SSL certificates, streams, and more.8 npmISC
- AlicenseBqualityCmaintenanceEnables AI agents to manage Nginx Proxy Manager (reverse proxies, streams, redirects, and Let's Encrypt certificates) through natural language commands.3028 npmMIT