ops-agent-mcp
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., "@ops-agent-mcpWhich deals are stuck in negotiation above R$ 100k?"
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.
ops-agent
An LLM agent that turns natural-language requests into audited, permission-gated actions on business systems — built on Anthropic tool use and exposed both as an HTTP API and as an MCP server.
"Which deals are stuck in negotiation above R$ 100k?" →
list_deals→ answer. "Close deal_102 as won, contract signed." →update_deal_stage→ refused unless writes are explicitly enabled, and either way the attempt is in the audit log.
Why this exists
Most "AI agent" demos let the model call anything with whatever arguments it produces. That is fine for a notebook and unacceptable for a CRM or a finance system. This project is a small, complete reference for the boring parts that make an agent deployable:
Allowlisted tools with schema-validated inputs. The model is treated as an untrusted client; every argument goes through Pydantic before touching a database.
Write gating. Mutating tools need an explicit opt-in per request and a global switch. A prompt injection hidden in a ticket subject cannot promote itself to a write.
Audit trail. Every tool call — allowed or refused — is appended to a JSONL log with timing, outcome and PII redaction.
One registry, three surfaces. The same
ToolRegistryproduces the Anthropic tool schema, the MCP tools and the test fixtures, so they cannot drift apart.Testable without network. The Anthropic client is injected behind a protocol; the agent loop is covered by unit tests with a scripted fake. Behavioural evals run against the real model when you want them to.
Related MCP server: Company API MCP Server
Architecture
flowchart LR
U[User / CLI / HTTP] -->|message| A[Agent loop]
M[MCP client<br/>Claude Desktop, IDE] -->|tool call| S[MCP server]
A -->|messages + tool schema| LLM[Claude<br/>Messages API]
LLM -->|tool_use blocks| A
A -->|validate · gate · execute| R[ToolRegistry]
S --> R
R --> T1[CRM tools<br/>accounts · deals · pipeline]
R --> T2[Ticket tools]
T1 & T2 --> DB[(SQLite<br/>synthetic data)]
R -->|every call| AUD[(Audit log<br/>JSONL, redacted)]Request lifecycle
Agent.run()sends the system prompt, the user message and the registry's tool schema.For each
tool_useblock the model returns, the registry checks the allowlist, refuses mutating tools when writes are not permitted, validates arguments, and executes.Results (or structured errors with
is_error=true) go back to the model astool_resultblocks. The loop repeats until the model answers ormax_iterationshits.Each tool call is recorded in the audit log before the loop continues.
Quickstart
git clone https://github.com/ramonpalopoli/ops-agent && cd ops-agent
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env # add your ANTHROPIC_API_KEY
# Ask something (read-only by default)
ops-agent "How much open pipeline do we have, by stage?"
# A write is refused until BOTH switches are on:
ops-agent "Move deal_101 to negotiation, customer agreed on scope" --allow-writes
OPS_AGENT_ALLOW_WRITES=true ops-agent "Move deal_101 to negotiation, customer agreed on scope" --allow-writesThe database is created and seeded with synthetic accounts, deals and tickets on first run
(data/ops.db). No real companies or people are involved.
HTTP API
export OPS_AGENT_API_TOKEN=$(python -c "import secrets;print(secrets.token_urlsafe(48))")
make api # uvicorn on 127.0.0.1:8000
curl -s http://127.0.0.1:8000/v1/chat \
-H "Authorization: Bearer $OPS_AGENT_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"message": "Which tickets are urgent?"}'
curl -s http://127.0.0.1:8000/v1/audit?limit=10 -H "Authorization: Bearer $OPS_AGENT_API_TOKEN"Route | Auth | Purpose |
| none | liveness |
| bearer | run the agent; body |
| bearer | last N audit events |
MCP server
Expose the same tools to any MCP client. Writes are controlled solely by
OPS_AGENT_ALLOW_WRITES on the server side — a client cannot escalate itself.
ops-agent-mcp # stdio transportClaude Desktop config: see mcp.example.json.
Tools
Tool | Writes | Input (validated) |
| no |
|
| no |
|
| no | optional |
| no | — |
| no | optional |
| yes |
|
| yes |
|
Adding a tool = one Pydantic model + one handler + one register() call in
src/ops_agent/tools/__init__.py. It shows up in the API, the MCP server and the schema
tests automatically.
Tests and evals
make test # 33 unit/integration tests, no network
make lint # ruff
make evals # behavioural evals against the real model (needs ANTHROPIC_API_KEY)Unit tests cover the agent loop (tool round-trip, write gating, iteration cap, error surfacing), every tool (including a SQL-injection attempt and LIKE-wildcard escaping), the HTTP API (auth, bounds, headers) and the MCP surface.
evals/scenarios.json asserts on behaviour rather than exact wording: which tools were
called, which were avoided, whether a refused write was reported honestly, and whether an
instruction smuggled into the prompt was ignored. Add a scenario, run make evals, ship.
Security decisions
Decision | Why |
Tool allowlist + Pydantic validation of every argument | The model is an untrusted client. Unknown tools and malformed arguments are rejected before any I/O. |
Parameterised SQL everywhere; | CWE-89. User text never reaches an identifier or unbound position. |
Writes require request opt-in and | Fail-secure default; defence in depth against prompt injection. |
Iteration cap | Bounded cost and latency; no runaway loops. |
Audit log with e-mail / phone / CPF redaction | CWE-532, LGPD: reviewable without leaking personal data. |
Bearer token compared with | CWE-208 timing attacks; weak-token misconfiguration fails at startup. |
Generic error responses; details only in server logs | CWE-209. |
| Baseline hardening for a JSON API. |
Random ticket ids ( | IDOR hardening (CWE-639). |
Secrets only via environment / git-ignored | CWE-798. |
Known limitations, on purpose: single SQLite file (swap for Postgres by changing db.py),
no per-user identity on the API (add OIDC in front of it), no rate limiting (put it at the
gateway), and the system prompt is a mitigation, not a control — the controls are in code.
Project layout
src/ops_agent/
agent.py # Messages API loop, guardrails, audit hooks
api.py # FastAPI surface
mcp_server.py # MCP surface (same registry)
cli.py # ops-agent CLI
config.py # pydantic-settings, validated at startup
db.py # SQLite schema + synthetic seed
audit.py # JSONL audit log with PII redaction
tools/
registry.py # allowlist, validation, write gating
crm.py # accounts, deals, pipeline
tickets.py # support tickets
tests/ # pytest, offline
evals/ # behavioural scenarios against the real modelRoadmap
Postgres backend and connection pooling
Per-user identity on the API and per-tool permissions (RBAC)
Streaming responses
Eval metrics over time (pass rate, tool precision) in CI
License
MIT — see LICENSE.
Available Tools
7 toolscreate_ticketA
Open a support ticket for an account. WRITES DATA: only call when the user explicitly asked to create a ticket. [writes data] Arguments: {"account_id": {"description": "e.g. acc_002", "pattern": "^acc_[0-9]{3,6}$", "title": "Account Id", "type": "string"}, "subject": {"maxLength": 140, "minLength": 5, "title": "Subject", "type": "string"}, "priority": {"default": "medium", "enum": ["low", "medium", "high", "urgent"], "title": "Priority", "type": "string"}}
| Name | Required | Description | Default |
|---|---|---|---|
| arguments | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It explicitly states 'WRITES DATA' and '[writes data]', which reveals that this is a mutating operation. It also adds a safety guideline about only calling after explicit user intent. However, it does not describe side effects beyond ticket creation (e.g., whether existing data is modified, whether permissions are required, or whether the operation is idempotent). For a write operation with no annotation coverage, this is moderate transparency.
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 main purpose is front-loaded and stated in one sentence. The JSON arguments block is long but necessary given the lack of schema descriptions. However, there is slight redundancy: 'WRITES DATA' and '[writes data]' convey the same information. Overall, the structure is clear and organized, with the usage guideline placed prominently.
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 create operation, the description covers the essential context: when to call, what it does, and how to structure arguments. An output schema exists, so return-value documentation is not needed here. It falls short of 5 because it omits any mention of prerequisites (e.g., whether the account must be valid) or expected behavior on failure, but these are not critical for a simple ticket creation flow.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the description provides a complete parameter breakdown: account_id with pattern and example, subject with length constraints, and priority with an enum and default. This adds substantial meaning beyond the minimal input schema, which only shows a generic 'arguments' object. The agent can correctly construct a call without external documentation.
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: 'Open a support ticket for an account.' It clearly indicates a create operation, and the explicit 'WRITES DATA' marker removes any ambiguity about its effect. Among siblings like get_deal, list_deals, list_open_tickets, and update_deal_stage, none compete with this create action, so the purpose is 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 gives an explicit trigger condition: 'only call when the user explicitly asked to create a ticket.' This tells the agent exactly when to invoke the tool and implicitly when not to. It does not explicitly list alternative tools, but since none of the siblings perform ticket creation, the guidance is sufficient for correct selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_dealA
Get one deal by id, including its account and recent stage history. Arguments: {"deal_id": {"description": "e.g. deal_101", "pattern": "^deal_[0-9]{3,6}$", "title": "Deal Id", "type": "string"}}
| Name | Required | Description | Default |
|---|---|---|---|
| arguments | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It does disclose the read-only retrieval action and the enriched payload (account, recent stage history), but it says nothing about not-found responses, invalid id handling, or authentication. It doesn't contradict any annotation, but the transparency is partial.
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 segments – a purpose sentence and an inline JSON parameter spec – with no filler. The parameter spec is slightly awkward embedded in prose, but it is still efficient and 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?
For a simple single-record getter with an output schema, the description covers the retrieval target and id format. It stops short of documenting error/not-found behavior and use-vs-sibling guidance, so it isn't fully complete.
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 formal schema only wraps a generic arguments object, so coverage is 0% and the description must compensate. It does so fully by providing deal_id's title, type, example ('deal_101'), and regex pattern, which is more than the input schema offers.
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: 'Get one deal by id,' and adds scope ('including its account and recent stage history'). The word 'one' and 'by id' differentiate it from list_deals/search_accounts, so an agent can tell it apart from the 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 implies the main use case – retrieving a specific deal when you know its id – but never names alternatives or states when not to use it (e.g., list_deals for all deals, update_deal_stage for changes). Usage must be inferred from the verb and resource.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_dealsB
List deals, optionally filtered by pipeline stage, ordered by amount. Arguments: {"stage": {"anyOf": [{"enum": ["qualification", "proposal", "negotiation", "closed_won", "closed_lost"], "type": "string"}, {"type": "null"}], "default": null, "description": "Filter by pipeline stage", "title": "Stage"}, "limit": {"default": 10, "maximum": 25, "minimum": 1, "title": "Limit", "type": "integer"}}
| Name | Required | Description | Default |
|---|---|---|---|
| arguments | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions ordering by amount and optional filtering, but does not disclose pagination behavior, whether the ordering is ascending or descending, what fields are returned, or whether this is a read-only operation. For a list tool with no annotation coverage, this is a notable gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence that front-loads the core action and key modifiers (filter by stage, ordered by amount). It is concise and readable, though it embeds the arguments JSON in the description string, which is redundant with the input schema and slightly clutters the text.
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, so return values are presumably documented there. However, with no annotations, no parameter descriptions in the schema, and no mention of pagination or ordering direction, the description leaves some operational details unclear. It is adequate for a simple list tool but not fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the input schema only wraps an 'arguments' object with additionalProperties allowed, providing no parameter-level documentation. The description does add meaning for 'stage' (filter by pipeline stage) and 'limit' (implied by the schema's default/max/min but not described in text), but it does not fully compensate for the complete lack of schema descriptions. The description names the filter and ordering but leaves the limit parameter's semantics to the schema's numeric constraints.
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 clear verb ('List') and resource ('deals'), and adds two specific behaviors: optional filtering by pipeline stage and ordering by amount. It does not explicitly distinguish itself from siblings like get_deal or pipeline_summary, but the resource and filter/order semantics make the core 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 implies when to use the tool: when you need a list of deals with optional stage filtering and amount ordering. It does not explicitly state when not to use it or name alternatives such as get_deal for a single deal or pipeline_summary for aggregate pipeline data. The context is clear enough for basic selection but lacks explicit routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_open_ticketsA
List open support tickets, most urgent first. Optional priority filter. Arguments: {"priority": {"anyOf": [{"enum": ["low", "medium", "high", "urgent"], "type": "string"}, {"type": "null"}], "default": null, "description": "Filter by priority", "title": "Priority"}, "limit": {"default": 10, "maximum": 25, "minimum": 1, "title": "Limit", "type": "integer"}}
| Name | Required | Description | Default |
|---|---|---|---|
| arguments | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full disclosure burden. It does reveal non-obvious behavior: only open tickets are returned, results are urgency-sorted, and the result size is capped (limit max 25). But it never states that the operation is read-only or non-mutating, and it says nothing about empty results, errors, or authorization requirements. The disclosure is adequate but not rich.
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 prose is tight and front-loaded — the first sentence states the core purpose, the second flags the filter. The embedded JSON is bulky and contains redundant structure (the anyOf wrapping with null), but since the real input schema documents nothing, it earns its place as the sole source of parameter semantics.
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 describing return values is not required. The description covers what is listed, the ordering, the filter options, and the limit constraints — enough for an agent to construct a correct call. The gaps are the missing usage-vs-alternative guidance and the lack of an explicit read-only confirmation, but the essential call contract is documented.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% — the input schema is a generic 'arguments' envelope with no property-level documentation. The description compensates by embedding the full parameter specification: the priority enum values (low, medium, high, urgent) with null default, and limit with default 10, minimum 1, maximum 25. It loses only stylistic points for delivering this as a raw JSON dump with redundant anyOf-null structure rather than clean prose.
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-resource pair ('List open support tickets') and adds a scope qualifier ('open') plus an ordering guarantee ('most urgent first'). This is unambiguous even without reading the schema, and nothing among the siblings (get_deal, list_deals, update_deal_stage, etc.) overlaps with listing tickets. It does not explicitly name a sibling to distinguish itself from, which keeps it just shy of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied rather than stated: the 'open' scope and 'most urgent first' ordering tell an agent what kind of query this serves, and 'Optional priority filter' hints at how to narrow it. However, there is no explicit when-to-use versus when-not-to-use guidance, no mention of alternatives, and no exclusions (e.g., closed tickets are out of scope but that is only inferred).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pipeline_summaryC
Aggregate deal count and BRL total per stage, plus open pipeline total. Arguments: {}
| Name | Required | Description | Default |
|---|---|---|---|
| arguments | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
There are no annotations, so the description carries the full burden of behavioral disclosure. It only describes the computation's outputs and does not state whether the tool is read-only, whether arguments are ignored, what 'open pipeline total' precisely means, or any permission requirements. 'Aggregate' implies no mutation, but this is not explicit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence is concise and front-loaded with the core purpose. However, the trailing 'Arguments: {}' is filler that merely restates schema information and does not earn its place, making the definition slightly less disciplined.
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 is minimally adequate for a no-parameter aggregation tool: it names the aggregations and an output schema exists. But it leaves ambiguities around the definition of 'open pipeline total,' whether any arguments can filter or scope the results, and the tool's read-only nature, so an agent gets only partial context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has one generic 'arguments' wrapper with 0% description coverage, and the description adds only 'Arguments: {}'. This is redundant with the schema's default null and does not clarify whether arbitrary properties are accepted, ignored, or forbidden, so it does not compensate for the missing schema descriptions.
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 (aggregate), a clear resource (deals), and the computed outputs (deal count, BRL total per stage, open pipeline total). This distinguishes it from siblings like list_deals and get_deal, which operate on individual deal records rather than roll-ups.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is given about when to use this tool versus list_deals, get_deal, or update_deal_stage. There are no conditions, exclusions, or alternative tool references, leaving the agent to infer when a summary is preferable to detailed listing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_accountsA
Find customer accounts by (partial) name. Returns id, segment, city, owner. Arguments: {"query": {"description": "Account name fragment", "maxLength": 80, "minLength": 1, "title": "Query", "type": "string"}, "limit": {"default": 10, "maximum": 25, "minimum": 1, "title": "Limit", "type": "integer"}}
| Name | Required | Description | Default |
|---|---|---|---|
| arguments | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries behavior disclosure itself. 'Find' implies a read-only lookup, and it discloses the matching mode and result fields. It does not explicitly state side-effect-free behavior or discuss pagination/auth, but for a simple search tool these are minor gaps.
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 tight sentences: the first gives purpose and output, the second packs the parameter constraints. 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 a simple search operation and an available output schema, the description covers the match mode, output fields, and all parameter bounds. It omits only optional guidance about when to prefer siblings, which is unnecessary since none of them search accounts.
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 structural schema only provides a generic 'arguments' wrapper, so the description compensates by fully documenting query (name fragment, length 1–80) and limit (default 10, max 25). This is substantial semantic value beyond what the input schema 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?
States a specific verb ('Find'), a resource ('customer accounts'), the matching mode ('partial name'), and the returned fields (id, segment, city, owner). This unambiguously distinguishes it from the sibling deal/ticket/pipeline tools, none of which search accounts.
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 context: use when looking up accounts by a name fragment. It does not explicitly name alternatives or exclusions, but none of the siblings are account-search tools, so the risk of mis-selection is low.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_deal_stageA
Move a deal to another pipeline stage. WRITES DATA: only call when the user explicitly asked for the change and provided a reason. [writes data] Arguments: {"deal_id": {"pattern": "^deal_[0-9]{3,6}$", "title": "Deal Id", "type": "string"}, "stage": {"enum": ["qualification", "proposal", "negotiation", "closed_won", "closed_lost"], "title": "Stage", "type": "string"}, "reason": {"description": "Why the stage is changing (audited)", "maxLength": 280, "minLength": 5, "title": "Reason", "type": "string"}}
| Name | Required | Description | Default |
|---|---|---|---|
| arguments | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no structured annotations provided, the description carries the full burden of behavioral disclosure. It clearly flags the operation as 'WRITES DATA' and notes the reason is 'audited', which conveys the mutation side effect and accountability. It does not discuss reversibility or downstream effects, but the essential behavioral traits are explicit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and guardrail are front-loaded in the first sentence, followed by a structured argument block. The embedded JSON is somewhat dense but necessary because the structured schema provides no parameter details, and every part contributes to a correct invocation.
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 combines a clear purpose, an explicit usage precondition, full parameter documentation, and an existing output schema. For a focused stage-update tool, this provides enough context for an agent to select and invoke the tool correctly without needing additional assumptions.
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 actual input schema is a generic 'arguments' bag with 0% schema description coverage, so the description must fully compensate. It does so by embedding a complete parameter spec: deal_id with pattern, stage with enum values, and reason with min/max length and audit semantics. This gives the agent all the parameter meaning it needs.
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-resource pair: 'Move a deal to another pipeline stage.' This unambiguously identifies the operation and clearly differentiates it from sibling read-focused tools like get_deal, list_deals, and pipeline_summary.
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 call the tool: 'only call when the user explicitly asked for the change and provided a reason.' This functions as both a when-to-use and when-not-to-use guardrail, which is especially valuable for a write operation.
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.
7 tool updates
v0.1.0- First observed
create_ticket - First observed
get_deal - First observed
list_deals - First observed
list_open_tickets - First observed
pipeline_summary - First observed
search_accounts - First observed
update_deal_stage
TDQS
Scored across 7 tools
Each tool targets a distinct resource and action: tickets have create/list, deals have get/list/update/pipeline summary, and accounts have search. There is no meaningful overlap that would cause an agent to select the wrong tool.
Most tool names follow a clear verb_noun pattern: create_ticket, get_deal, list_deals, list_open_tickets, search_accounts, update_deal_stage. The one deviation is pipeline_summary, which uses a noun phrase rather than an action verb, but the naming remains readable and predictable overall.
Seven tools is a well-scoped set for an ops agent handling accounts, deals, and support tickets. Each tool covers a necessary operation without redundancy or bloat.
The deal workflow is reasonably covered with list/get/stage updates and pipeline totals, but ticket support is incomplete: there is no way to fetch a single ticket, update it, or close/resolve it. Account coverage is also limited to search, with no account detail endpoint.
Maintenance
Related MCP Connectors
Find, vet, and run MCP tools through a secure audited gateway with prompt-injection risk scoring
Unified MCP Server is a remote MCP connector for AI agents and vertical AI products that provides access to 22,000+ authorized SaaS tools across 400+ integrations and 24 categories directly inside LLMs (Claude, GPT, Gemini, Cohere). Tools operate only on explicitly authorized customer connections, enabling agents to safely read and write against live third-party systems.
Let AI agents query data and act across all your business apps via MCP.
Your org's AI agents, tasks, runs, search, and brain files as MCP tools and resources.
Related MCP Servers
- -licenseNot gradedqualityBmaintenanceEnables users to interact with a set of tools via an LLM agent, allowing natural language requests to be processed and executed through the MCP server.-
- FlicenseNot gradedqualityCmaintenanceExposes internal company services as LLM-callable MCP tools, enabling AI agents to perform business operations like customer management, order processing, and support ticketing through natural language.-
- FlicenseNot gradedqualityBmaintenanceEnables natural-language Q&A, human-approved actions, and dashboard generation over a data ontology via MCP.-
- FlicenseNot gradedqualityCmaintenanceProvides MCP tools for hybrid knowledge base search, grounded Q&A with citations, agent execution, and ticket/account lookups.-