Tool Discovery and Scope Filtering
How Mandraki's MCP server dynamically filters available tools based on your API token's scopes, and how to use tools/list to discover what your integration can do.
How Tool Discovery Works
When an MCP client sends a tools/list request, the Mandraki MCP server does not return a fixed list. Instead, it queries the internal ToolBroker — the same registry that powers Mandraki’s built-in AI assistant — and filters the results based on the requesting token’s scopes.
This means your integration only sees tools it is permitted to use. A token with tasks:read and tasks:write scopes will see task tools but not calendar or drive tools.
Scope-to-Module Mapping
API token scopes map to internal app modules. The MCP server uses this mapping to decide which tools to include in the tools/list response:
| Scope prefix | Modules exposed | Example tools |
|---|---|---|
tasks | tasks | tasks.create-task, tasks.list-tasks, tasks.update-task |
calendar | calendar | calendar.list-events, calendar.create-event, calendar.check-availability |
drive, files | drive | drive.search-files, drive.get-file-info |
channels, messages | chat, messages | chat.search-messages, chat.get-thread-context |
mail | mail.search-mail, mail.read-email, mail.compose-draft | |
calls | call | Call-related tools |
teams | teams | Team management tools |
users | users | User lookup tools |
A single scope prefix can expose multiple modules. For example, channels exposes both chat and messages modules because channel history and message operations are closely related.
Example: tools/list Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
Response (token with tasks:read + tasks:write scopes)
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "tasks.create-task",
"description": "Create a new task in a project",
"inputSchema": {
"type": "object",
"properties": {
"title": { "type": "string", "description": "Task title" },
"projectId": { "type": "string", "description": "Project to create the task in" },
"description": { "type": "string", "description": "Task description" },
"assigneeId": { "type": "string", "description": "User ID to assign the task to" },
"priority": { "type": "string", "enum": ["LOW", "MEDIUM", "HIGH", "URGENT"] },
"dueDate": { "type": "string", "description": "Due date in ISO 8601 format" }
},
"required": ["title"]
}
},
{
"name": "tasks.list-tasks",
"description": "List tasks, optionally filtered by project or assignee",
"inputSchema": {
"type": "object",
"properties": {
"projectId": { "type": "string" },
"assigneeId": { "type": "string" },
"status": { "type": "string", "enum": ["OPEN", "COMPLETED"] }
}
}
},
{
"name": "tasks.update-task",
"description": "Update an existing task",
"inputSchema": {
"type": "object",
"properties": {
"taskId": { "type": "string" },
"title": { "type": "string" },
"description": { "type": "string" },
"priority": { "type": "string" },
"dueDate": { "type": "string" },
"assigneeId": { "type": "string" }
},
"required": ["taskId"]
}
},
{
"name": "tasks.complete-task",
"description": "Mark a task as completed",
"inputSchema": {
"type": "object",
"properties": {
"taskId": { "type": "string" }
},
"required": ["taskId"]
}
},
{
"name": "tasks.get-my-tasks",
"description": "Get tasks assigned to the current user",
"inputSchema": {
"type": "object",
"properties": {}
}
},
{
"name": "tasks.add-comment",
"description": "Add a comment to a task",
"inputSchema": {
"type": "object",
"properties": {
"taskId": { "type": "string" },
"content": { "type": "string" }
},
"required": ["taskId", "content"]
}
}
]
}
}
Filtering by App
You can pass an appId parameter to tools/list to filter by a specific app module:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {
"appId": "calendar"
}
}
This returns only calendar tools (assuming your token has calendar:read or calendar:write scopes).
Scope Enforcement on tools/call
Scope filtering is not just cosmetic. When you call tools/call, the server verifies that the tool’s module is within your token’s allowed scopes. If you attempt to call a tool outside your scopes, you get an error:
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "calendar.create-event",
"arguments": { "title": "Meeting" }
}
}
Response (token lacks calendar:* scopes):
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "Tool 'calendar.create-event' is not within this token's scopes"
}
],
"isError": true
}
}
Tool Naming Convention
All tool names follow the pattern module.action:
tasks.create-task— module istasks, action iscreate-taskdrive.search-files— module isdrive, action issearch-fileschat.search-messages— module ischat, action issearch-messages
The module prefix determines which scope is required. A tool in the tasks module requires a scope starting with tasks:.
Read vs Write Scopes
Some modules have separate read and write scopes:
tasks:read— allowstasks.list-tasks,tasks.get-my-taskstasks:write— allowstasks.create-task,tasks.update-task,tasks.complete-task,tasks.add-comment
Grant read scopes for monitoring and reporting integrations. Grant write scopes when the integration needs to create or modify data.