Module 11 · cognitive feature
Dynamic tool synthesis over MCP
Hardcoding every enterprise API an agent might need is impossible. Hand it the OpenAPI spec instead: operations become MCP descriptors, scopes decide what is exposed, and a denylist keeps dangerous operations out of the manifest entirely. A tool the model never sees is a tool it cannot be talked into calling.
$ python -m fde_toolkit tools
Granted scopes
the agent's service principal
Denylist
never exposed, whatever the scope
Synthesised tool manifest
3 of 4 operations exposed
- exposed
get_customerGET /customers/{customerId}Fetch a customer dossier including KYC status.
scopes: customer.read · risk low
{ "name": "get_customer", "description": "Fetch a customer dossier including KYC status.", "inputSchema": { "type": "object", "properties": { "customerId": { "type": "string", "description": "path parameter" } }, "required": [ "customerId" ] }, "annotations": { "readOnlyHint": true, "destructiveHint": false, "requiresApproval": false } } - exposed
list_transactionsGET /accounts/{accountId}/transactionsList transactions for an account within a date range.
scopes: transactions.read · risk low
{ "name": "list_transactions", "description": "List transactions for an account within a date range.", "inputSchema": { "type": "object", "properties": { "accountId": { "type": "string", "description": "path parameter" }, "from": { "type": "string", "description": "query parameter" }, "to": { "type": "string", "description": "query parameter" }, "minAmount": { "type": "number", "description": "query parameter" } }, "required": [ "accountId" ] }, "annotations": { "readOnlyHint": true, "destructiveHint": false, "requiresApproval": false } } - exposed
create_paymentPOST /paymentsapprovalInitiate an outbound payment.
scopes: payments.write · risk high
{ "name": "create_payment", "description": "Initiate an outbound payment.", "inputSchema": { "type": "object", "properties": { "sourceAccount": { "type": "string" }, "beneficiary": { "type": "string" }, "amount": { "type": "number" }, "currency": { "type": "string" } }, "required": [ "amount", "beneficiary", "currency", "sourceAccount" ] }, "annotations": { "readOnlyHint": false, "destructiveHint": true, "requiresApproval": true } } - withheld
debug_dumpGET /internal/debug/dumpDump raw table contents for support engineers.
scopes: admin · risk high
On the FDE denylist: never exposed autonomously.
Call synthesis
natural language → HTTP
list_transactionshttps://corebank.internal/api/v11/accounts/AE070331234567890123456/transactions?from=2026-01-01&to=2026-03-31
- · Read-only; the date range was inferred from 'this quarter'.
Why this beats glue code
- No redeploy per endpoint. The client publishes a new operation and the agent discovers it.
- Authorisation stays where it belongs. Revoke a scope and the tool disappears from the manifest — no prompt edit.
- Annotations carry intent.
readOnlyHintandrequiresApprovallet the orchestrator gate writes without parsing the description. - Refusal is structural. Turn the denylist off above and watch a dangerous operation enter the manifest — that is the demo to run for a security team.