Yichus / Reference / API MCP tools
api_access_check
Check resource policies from typed IR: OwnerScoped keys must derive from the runtime Principal; Guarded operations and row uses must follow supported declared guards; GuardedOrRoles also permits access when every route reaching the operation requires every listed role. An empty guards list is role-only. PublicReadRoleWrite permits reads and queries on any route but requires every listed route role for mutations, including ID allocation. Public imposes no owner-key or guard discipline. Reports holds/violated/inconclusive. Also returns routes, every declared route with discloses: each stored field path (table.field[].field) its response may carry, kind copied, computed, guard (it only decides which reply is sent) or released, via the release for released, precise false for a possible reach. An empty discloses list means the complete walk found no stored field; discloses is null, with disclosesBlocked reasons, when the walk cannot establish it. Guard use does not prove that the guard expresses the intended business rule, and route authority relies on the server enforcing authenticated identities and roles.
Kind: AccessCheck. Origin: Yichus/Mcp::catalog.
CLI: yichus access — one implementation: both run ApiChecks.accessJson.
Parameters
sources(required, array) — JSON array of {fileName, source} Bosatsu files.
Example
This response was produced by calling this tool with the displayed request when these docs were generated. Analysis examples use the owner-scoped notes specimen; scaffold examples supply a resource specification.
Request
{
"sources": [
{
"fileName": "notes-api.bosatsu",
"source": "package Demo/Service/NotesApi\n\n# Owner-scoped notes API. One row per caller, keyed by Principal.user_id.\n# `yichus api verify` / api_access_check prove the scoping from Matchless IR.\n\nfrom Yichus/IO import IO, flat_map\nfrom Yichus/Access import Principal, AccessRule, AccessSpec, OwnerScoped\nfrom Yichus/Data import Db, Table, table, db_read, db_write, db_delete\nfrom Yichus/Service import handler, route, service_def, ReadPerm, WritePerm, DeletePerm\n\nexport (notes_api, access_rules, Note())\nexposes (Yichus/Access, Yichus/Service)\n\nstruct Note(title: String)\n\naccess_rules = AccessSpec([\n AccessRule(\"notes\", OwnerScoped),\n])\n\ndef notes_table(db: Db) -> Table[List[Note]]:\n table(db, \"notes\")\n\ndef list_notes(db: Db, p: Principal) -> IO[List[Note]]:\n Principal(uid, _) = p\n db_read(notes_table(db), uid)\n\ndef put_notes(db: Db, p: Principal, items: List[Note]) -> IO[List[Note]]:\n Principal(uid, _) = p\n db_write(notes_table(db), uid, items)\n\ndef add_note(db: Db, p: Principal, item: Note) -> IO[List[Note]]:\n Principal(uid, _) = p\n items <- flat_map(db_read(notes_table(db), uid))\n db_write(notes_table(db), uid, [item, *items])\n\ndef clear_notes(db: Db, p: Principal) -> IO[Unit]:\n Principal(uid, _) = p\n db_delete(notes_table(db), uid)\n\nnotes_api = service_def(\n \"notes\",\n [\n route(\"/notes\", handler(\"list_notes\", list_notes), [ReadPerm(\"notes\")]),\n route(\"/notes/put\", handler(\"put_notes\", put_notes), [WritePerm(\"notes\")]),\n route(\"/notes/add\", handler(\"add_note\", add_note), [ReadPerm(\"notes\"), WritePerm(\"notes\")]),\n route(\"/notes/clear\", handler(\"clear_notes\", clear_notes), [DeletePerm(\"notes\")]),\n ]\n)\n"
}
]
}
Response
{
"ok": true,
"tool": "api_access_check",
"report": {
"proven": true,
"specError": null,
"findings": [
{
"package": "Demo/Service/NotesApi",
"binding": "list_notes",
"resource": "notes",
"operation": "db_read",
"kind": "OwnerKeyProven",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"package": "Demo/Service/NotesApi",
"binding": "put_notes",
"resource": "notes",
"operation": "db_write",
"kind": "OwnerKeyProven",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"package": "Demo/Service/NotesApi",
"binding": "add_note",
"resource": "notes",
"operation": "db_read",
"kind": "OwnerKeyProven",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"package": "Demo/Service/NotesApi",
"binding": "add_note",
"resource": "notes",
"operation": "db_write",
"kind": "OwnerKeyProven",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"package": "Demo/Service/NotesApi",
"binding": "clear_notes",
"resource": "notes",
"operation": "db_delete",
"kind": "OwnerKeyProven",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
}
],
"resources": [
{
"resource": "notes",
"policy": "OwnerScoped",
"status": "holds",
"proven": true,
"findings": [
{
"package": "Demo/Service/NotesApi",
"binding": "list_notes",
"resource": "notes",
"operation": "db_read",
"kind": "OwnerKeyProven",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"package": "Demo/Service/NotesApi",
"binding": "put_notes",
"resource": "notes",
"operation": "db_write",
"kind": "OwnerKeyProven",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"package": "Demo/Service/NotesApi",
"binding": "add_note",
"resource": "notes",
"operation": "db_read",
"kind": "OwnerKeyProven",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"package": "Demo/Service/NotesApi",
"binding": "add_note",
"resource": "notes",
"operation": "db_write",
"kind": "OwnerKeyProven",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
},
{
"package": "Demo/Service/NotesApi",
"binding": "clear_notes",
"resource": "notes",
"operation": "db_delete",
"kind": "OwnerKeyProven",
"status": "holds",
"detail": "key derives from the authenticated Principal (user_id or owner_key)"
}
]
}
]
},
"routes": [
{
"path": "/notes",
"handler": "list_notes",
"binding": "Demo/Service/NotesApi::list_notes",
"authority": "authenticated",
"discloses": [
{
"path": "notes",
"kind": "copied",
"via": null,
"precise": true
},
{
"path": "notes[].title",
"kind": "copied",
"via": null,
"precise": true
}
],
"disclosesBlocked": null
},
{
"path": "/notes/add",
"handler": "add_note",
"binding": "Demo/Service/NotesApi::add_note",
"authority": "authenticated",
"discloses": [
{
"path": "notes",
"kind": "computed",
"via": null,
"precise": true
},
{
"path": "notes[].title",
"kind": "computed",
"via": null,
"precise": true
}
],
"disclosesBlocked": null
},
{
"path": "/notes/clear",
"handler": "clear_notes",
"binding": "Demo/Service/NotesApi::clear_notes",
"authority": "authenticated",
"discloses": [],
"disclosesBlocked": null
},
{
"path": "/notes/put",
"handler": "put_notes",
"binding": "Demo/Service/NotesApi::put_notes",
"authority": "authenticated",
"discloses": [],
"disclosesBlocked": null
}
]
}
Run tools in the browser: api-mcp.html?webmcp=1.
Read the result according to this tool’s scope: static checks, bounded execution checks, and descriptive diagrams answer different questions. A successful call is not a general approval of the program. The safety and permissions guide compares the checks and provides editable ownership, guard, and role examples.