Skip to main content

  1. Agentycs
  2. Developers
  3. MCP and tools

Give agents tools without giving them the keys.

Every application exposes its operations as Model Context Protocol tools, and every tool call passes exactly the same per-operation permission check as the equivalent REST or WebSocket call.

Your applications, as tools #

Each application has its own MCP entry point. The tools it offers are the operations it already declared, so the catalogue cannot drift from what the application actually does, and an agent sees only what its identity is allowed to see.

Ask an application what tools it offers · JSON
// POST /api/apps/inspections/mcp
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }

// Response, for a caller who may read findings but not close them.
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      { "name": "query.open_findings", "description": "Open findings for a site" },
      { "name": "query.inspection_history", "description": "Past inspections" },
      { "name": "http.request", "description": "Authenticated app HTTP routes" }
    ]
  }
}

The catalogue is derived from the operations the application declared, so it cannot drift from what the application actually does. The mutation that closes a finding is absent because this caller may not close one: two agents with different identities legitimately see two different catalogues.

Call an application's tool over MCP · JSON
// POST /api/apps/inspections/mcp
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "query.open_findings",
    "arguments": { "site_id": "FAW-014" }
  }
}

Each application has its own MCP entry point at /api/apps/{app}/mcp, and its live queries and mutations become query.* and mutation.* tools. A tool call passes the same per-operation permission check as the REST and WebSocket equivalents above.

An agent only ever sees what the identity behind it is allowed to see. The model is not the boundary.

MCP is not a separate authorisation model #

This is the part most agent stacks get wrong. A tool is a privileged action, so it has to inherit an identity and a permission decision rather than borrow an ambient credential. A tool call here resolves through the same single decision as any other request, and there is no path where the protocol itself becomes the softer way in.

  • Application access and workspace scope checked before any tool is offered
  • A per-operation capability check on every individual call
  • Workspace context derived from validated session or token state, never from tool arguments
  • Every privileged read or action correlated to the identity and session behind it, in a tamper-evident record
What a denial looks like · Shell
$ curl -i https://agentycs.example.com/api/apps/inspections/close_finding \
    -H "Authorization: Bearer $AGENTYCS_API_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"finding_id": "FAW-014-22"}'

HTTP/2 403
x-agentycs-error-code: permission_denied
x-agentycs-request-id: 01JQ8Z5W3K4M6P8R0T2V4X6Y8A

A valid identity that is not allowed this operation. The class is in the header, not buried in a message, so a client can tell a denial from an outage: 403 will not change on retry, while a 503 from the same endpoint means the authorisation backend was briefly unreachable and a retry is correct. Quote the request id and the trace, the logs and the access record all resolve to this call.

Tools a model can reach #

Generation is only half of it. A governed tool-calling surface lets a model invoke platform and external tools mid-answer, each behind a capability check, with allowlists, credential references and rate limits on outbound targets.

  • Sovereign, self-hosted web search: privacy-preserving metasearch with safe fetching and citation extraction
  • Hybrid retrieval over your own documents and records, for grounded answers
  • Platform operations, so an agent can act rather than only advise
  • External targets behind allowlists, rate limits and breakers

Grounded, not guessing #

Retrieval fuses keyword precision and semantic recall into one ranked result, tunable from pure keyword to pure semantic. When a question becomes a query, the planner produces permission-aware SQL, or asks to clarify, or declines.

  • Keyword and vector search fused by reciprocal-rank into one relevance ranking
  • Answers cite the exact rows and documents they were drawn from
  • A generated query is bounded and read-only, like any hand-written one
  • An agent only ever retrieves what the identity behind it is allowed to see