Built-in Tools¶
Reference guide for Preloop's built-in MCP tools.
Overview¶
Preloop provides two categories of built-in tools:
- Always-Available Tools - Available to all users immediately
- Tracker-Dependent Tools - Only available when trackers are connected
All built-in tools can be protected by the Safety Layer with access rules and approval workflows.
Access Rules & Tool Configuration¶
Each tool supports multiple access rules with fine-grained control:
- Actions:
allow,deny, orrequire_approval— determine whether a tool call proceeds, is blocked, or needs human approval - CEL conditions: Match rule application to specific argument values (e.g. production vs staging, high-value transactions)
- Priority ordering: Rules are evaluated in order; the first matching rule applies
See CEL Expressions for condition syntax and examples.
Always-Available Tools¶
These tools work immediately without any setup.
request_approval¶
Request approval for any action with custom context.
Purpose: Let agents explicitly request approval before risky operations
Arguments:
reason(string, required) - Why approval is neededcontext(object, optional) - Additional contextapproval_workflow_id(string, optional) - Specific approval workflow to use
Returns:
{
"approved": true,
"approved_by": "alice@acme.com",
"approved_at": "2025-01-25T10:30:00Z",
"approval_request_id": "req_abc123"
}
Example:
result = request_approval(
reason="About to deploy version 2.3.0 to production",
context={
"version": "2.3.0",
"environment": "production",
"changes": ["Added new API", "Fixed bug #123"]
}
)
if result.approved:
deploy(version="2.3.0", env="production")
When to use:
- Agent needs to decide when to request approval
- Want to provide rich context about WHY approval is needed
- Multi-step workflows where timing matters
Difference from policy-gated tools:
- Policy-gated tools: Automatic interception
request_approval: Explicit agent decision
See MCP Tool Integration for details.
Tracker-Dependent Tools¶
These tools only appear when you've connected at least one tracker (GitHub, GitLab, or Jira).
Why Tracker-Dependent?¶
Built-in issue tools operate on tracker data: - No tracker = No issues to query - Connect GitHub → tools work with GitHub issues - Connect Jira → tools work with Jira tickets
Connect GitHub, GitLab, or Jira from the console before using tracker-dependent built-in tools.
Issue Management Tools¶
get_issue¶
Fetch full details for a single issue.
Arguments:
issue_id(string, required) - Issue ID (e.g., "PROJ-123", "#456")
Returns:
{
"id": "PROJ-123",
"title": "Fix login bug",
"description": "Users unable to login...",
"status": "in_progress",
"priority": "high",
"assignee": "alice@acme.com",
"labels": ["bug", "security"],
"created_at": "2025-01-20T10:00:00Z",
"updated_at": "2025-01-25T14:30:00Z"
}
Example:
issue = get_issue(issue_id="PROJ-123")
print(f"Issue: {issue.title}")
print(f"Status: {issue.status}")
When to preloop:
- ⚪ Usually NOT needed (read-only operation)
- ✅ Preloop if reading sensitive/confidential issues
create_issue¶
Create a new issue in connected tracker.
Arguments:
title(string, required) - Issue titledescription(string, optional) - Detailed descriptionpriority(string, optional) - Priority levellabels(list, optional) - Labels/tagsassignee(string, optional) - Assign to userproject(string, optional) - Project/repo name
Returns:
{
"id": "PROJ-124",
"url": "https://github.com/acme/repo/issues/124",
"created_at": "2025-01-25T15:00:00Z"
}
Example:
issue = create_issue(
title="Add user authentication",
description="Implement OAuth2 authentication",
priority="high",
labels=["feature", "security"],
assignee="bob@acme.com"
)
print(f"Created issue: {issue.url}")
When to preloop:
- ✅ Always - Creating issues can spam your tracker
- ✅ Especially for bulk operations
- ✅ When AI agents create issues automatically
Recommended policy:
tool: create_issue
approval: required
approvers: [team_lead@acme.com]
notification:
email: true
slack: true
update_issue¶
Modify an existing issue.
Arguments:
issue_id(string, required) - Issue to updatetitle(string, optional) - New titledescription(string, optional) - New descriptionstatus(string, optional) - New statuspriority(string, optional) - New prioritylabels(list, optional) - Update labelsassignee(string, optional) - Reassign
Returns:
{
"id": "PROJ-123",
"updated_fields": ["status", "priority"],
"updated_at": "2025-01-25T15:30:00Z"
}
Example:
When to preloop:
- ✅ High priority/critical issues - Require approval for status changes
- ✅ Bulk operations - Updating many issues at once
- ⚪ Low priority issues - Usually safe without approval
Recommended policies:
Conditional (only high priority):
tool: update_issue
condition: args.priority in ["critical", "high"]
approval: required
approvers: [product_team]
Status-based:
tool: update_issue
condition: has(args.status) && args.status == "closed"
approval: required
approvers: [team_lead@acme.com]
search¶
Search across all issues in connected trackers.
Arguments:
query(string, required) - Search queryfilters(object, optional) - Additional filtersstatus- Filter by statuspriority- Filter by priorityassignee- Filter by assigneelabels- Filter by labelscreated_after- Filter by creation datelimit(number, optional) - Max results (default: 20)
Returns:
{
"results": [
{
"id": "PROJ-123",
"title": "Fix login bug",
"score": 0.95,
"tracker": "github"
},
...
],
"total": 42,
"query": "login bug"
}
Example:
results = search(
query="authentication bug",
filters={
"status": "open",
"priority": ["high", "critical"]
},
limit=10
)
for issue in results.results:
print(f"{issue.id}: {issue.title}")
When to preloop:
- ⚪ Usually NOT needed (read-only)
- ✅ Preloop if searching sensitive/confidential data
Issue Intelligence Tools¶
estimate_compliance¶
Check if an issue meets "Definition of Ready" criteria.
Arguments:
issue_id(string, required) - Issue to check
Returns:
{
"compliance_score": 0.75,
"missing_fields": ["acceptance_criteria", "story_points"],
"suggestions": [
"Add acceptance criteria to clarify done state",
"Estimate story points for sprint planning"
],
"compliant": false
}
Example:
compliance = estimate_compliance(issue_id="PROJ-123")
if not compliance.compliant:
print(f"Missing: {', '.join(compliance.missing_fields)}")
print("Suggestions:")
for suggestion in compliance.suggestions:
print(f" - {suggestion}")
When to preloop:
- ⚪ Usually NOT needed (analysis only, no modifications)
Use cases:
- Automated issue quality checks
- Pre-sprint grooming
- Compliance reporting
improve_compliance¶
Get AI-powered suggestions to improve issue compliance.
Arguments:
issue_id(string, required) - Issue to improve
Returns:
{
"suggestions": [
{
"field": "acceptance_criteria",
"current": null,
"suggested": "- User can log in with email\n- User can log in with OAuth\n- Error messages are clear"
},
{
"field": "story_points",
"current": null,
"suggested": 5
}
]
}
Example:
improvements = improve_compliance(issue_id="PROJ-123")
for suggestion in improvements.suggestions:
print(f"Field: {suggestion.field}")
print(f"Suggested: {suggestion.suggested}")
When to preloop:
- ✅ If auto-applying - Require approval before updating issue
- ⚪ If just showing suggestions - No approval needed
Recommended policy (if auto-apply):
tool: improve_compliance
condition: args.auto_apply == true
approval: required
approvers: [team_lead@acme.com]
Tool Availability Matrix¶
| Tool | Always Available | Requires Tracker | Read-Only | Should Preloop? |
|---|---|---|---|---|
request_approval |
✅ | ❌ | ❌ | ⚪ N/A |
get_issue |
❌ | ✅ | ✅ | ⚪ Usually no |
create_issue |
❌ | ✅ | ❌ | ✅ Yes |
update_issue |
❌ | ✅ | ❌ | ✅ Conditionally |
search |
❌ | ✅ | ✅ | ⚪ Usually no |
estimate_compliance |
❌ | ✅ | ✅ | ⚪ No |
improve_compliance |
❌ | ✅ | ❌ | ✅ If auto-apply |
Prelooping Strategies¶
Read-Only Tools (Low Risk)¶
Tools: get_issue, search, estimate_compliance
Strategy: Usually don't preloop - No side effects - No data modification - Fast and safe
Exception: Sensitive data
Write Tools (Medium-High Risk)¶
Tools: create_issue, update_issue, improve_compliance
Strategy: Preloop conditionally
create_issue:
update_issue:
# Only for high-priority or status changes
tool: update_issue
condition: |
args.priority in ["critical", "high"] ||
has(args.status)
approval: required
improve_compliance:
# Only if auto-applying
tool: improve_compliance
condition: has(args.auto_apply) && args.auto_apply == true
approval: required
Error Handling¶
Common Errors¶
Tool not available:
{
"error": "Tool not found: create_issue",
"code": -32601,
"message": "No trackers connected. Connect GitHub, GitLab, or Jira to use this tool."
}
Solution: Connect a tracker in Settings → Trackers
Invalid issue ID:
{
"error": "Issue not found: INVALID-123",
"code": -32000,
"message": "Issue INVALID-123 does not exist in any connected tracker"
}
Solution: Verify issue ID format matches your tracker
Permission denied:
{
"error": "Permission denied",
"code": -32002,
"message": "User lacks permission to create issues in project PROJ"
}
Solution: Check tracker permissions or contact admin