Custom Agent Integration
For developers building custom agents that connect directly to SkillzDrive via MCP.
Connecting your own agent gives you real-time access to the full skill library — dynamic discovery, on-demand execution, and programmatic drive management. This guide covers skill awareness, UI feedback, async execution, and caching patterns to make your integration production-ready.
Not building a custom agent?
On This Page
A. Making Your Agent Aware of Skills
Baseline: install the guide skill
Connecting MCP and expecting the AI to use it is the #1 integration mistake. Most LLMs will NOT call MCP tools unless explicitly told to.
Install the skillzdrive-mcp-guide skill locally alongside your agent. Once installed, the MCP server's briefing (plus skills_getStarted) teaches your agent all 29 tools, execution workflows, error handling patterns, and fallback chains — no system prompt engineering required.
With the baseline covered, the two patterns below address production concerns the briefing can't — architectural choices that depend on how your agent is structured.
Pattern 1: Pinned Skills for Sub-Agents
In orchestrator/sub-agent architectures, the orchestrator discovers skills dynamically (via searchSkills or listSkills), then pins a specific skill or script to a sub-agent for efficiency. The sub-agent skips discovery entirely and goes straight to execution.
// Orchestrator: discover dynamically, then delegate
const { results } = await mcpClient.callTool("skills_searchSkills", {
query: userTask, // e.g. "merge these PDFs"
});
const skill = results[0]; // best match
// Pin the skill slug to a sub-agent's context
const subAgentPrompt = `You are a ${skill.name} specialist.
Use skill slug: ${skill.slug}
Go directly to skills_listScripts → skills_runScript → skills_readFile → skills_closeSession.
Do NOT call searchSkills or listSkills — your skill is already assigned.`;
// Sub-agent now runs with zero discovery overhead
await spawnSubAgent(subAgentPrompt);Tip
Pattern 2: Caching Strategy
Don't re-fetch skill lists on every message. Skills and scripts don't change mid-conversation.
| What to Cache | Cache Duration | When to Refresh |
|---|---|---|
| listSkills results | Entire session | Agent restart |
| listScripts per slug | Entire session | Agent restart |
| runScript results | Never cache | Every execution is unique |
B. UI Feedback for Tool Calls
The #2 mistake
What to show at each stage
| Stage | What to Show | Example |
|---|---|---|
| searchSkills | Searching for skills... | Spinner + message |
| listScripts | Found merge.py — preparing... | Status update |
| runScript | Processing your PDF... | Progress indicator |
| readFile | Reading results... | Brief flash |
| Success | Formatted result | Code block or rendered output |
| Error | Error + suggestions | Alert with recovery action |
Implementation pattern
// Hook into MCP tool call events for real-time UI feedback
agent.onToolCall((toolName, args) => {
switch (toolName) {
case "skills_searchSkills":
showStatus("Searching for skills...");
break;
case "skills_listScripts":
showStatus(`Loading scripts for ${args.skillSlug}...`);
break;
case "skills_runScript":
showStatus(`Running ${args.scriptName}...`);
break;
case "skills_readFile":
showStatus("Reading results...");
break;
case "skills_closeSession":
// No UI needed — cleanup is silent
break;
}
});
agent.onToolResult((toolName, result) => {
if (toolName === "skills_runScript") {
if (result.exitCode === 0) {
showStatus("Script completed successfully", "success");
} else {
showStatus(result.error || "Script failed", "error");
}
}
});Displaying errors well
SkillzDrive errors are structured for great UX. Use all the fields:
// Error response structure
{
"error": "skill_not_found", // Machine-readable code
"message": "No skill with slug 'pdff'", // Show this to users
"suggestions": [ // Show as recovery options
"Did you mean 'pdf'?",
"Use skills_searchSkills to find skills"
],
"_workflow": { // Use for automatic recovery
"nextSteps": [
{ "tool": "skills_searchSkills", "example": { "query": "pdf" } }
]
}
}
// Display pattern:
// 1. Show `message` as the error text
// 2. Show `suggestions[0]` as a clickable recovery action
// 3. Use `_workflow.nextSteps` to auto-recover if possible
// 4. NEVER show raw JSON-RPC errors to usersC. Async Script Execution
Warning
Recommended async pattern
| # | Step | What Happens |
|---|---|---|
| 1 | Start the script | runScript with reuseSession: true |
| 2 | Acknowledge immediately | "I'm processing your request..." |
| 3 | Continue conversation | Let users ask other questions while script runs |
| 4 | Await completion | Script finishes, read output |
| 5 | Notify with results | "Your PDF merge is complete!" |
async function executeSkillAsync(
mcpClient: McpClient,
skillSlug: string,
scriptName: string,
args?: string[]
) {
// 1. Show immediate feedback
notify("Starting skill execution...", "loading");
// 2. Run the script
const runResult = await mcpClient.callTool("skills_runScript", {
skillSlug,
scriptName,
args,
reuseSession: true,
});
// 3. Handle failure
if (runResult.exitCode !== 0) {
notify(`Error: ${runResult.error}`, "error");
return null;
}
// 4. Read the output
const output = await mcpClient.callTool("skills_readFile", {
sessionId: runResult.sessionId,
filePath: "/tmp/last_run.out",
});
// 5. Show results
notify("Skill completed!", "success");
displayOutput(output.content);
// 6. Clean up
await mcpClient.callTool("skills_closeSession", {
sessionId: runResult.sessionId,
});
return output.content;
}Handling large output
output.hasMore is true, paginate with startLine and limit parameters. The default returns the first 200 lines.D. Integration Checklist
Run through this before shipping your integration. Every checked box is a better user experience.