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
The #1 mistake
Connecting MCP and expecting the AI to use it. Most LLMs will NOT call MCP tools unless explicitly told to. Your agent needs to know what skills exist and when to use them.
The fastest fix — even for custom agents — is downloading and installing the skillzdrive-mcp-guide skill locally alongside your agent. Once installed, it teaches your agent all 20 tools, the correct execution workflows, and error handling patterns. This eliminates most of the system prompt work in Pattern 1 below and dramatically reduces integration time.
Pattern 1: System Prompt Injection
If you're not using the guide skill, add skill awareness directly to your agent's system prompt. The key advantage of MCP is that the skill catalog is dynamic — teach your agent to discover skills on the fly rather than listing specific ones.
You have access to SkillzDrive skills via MCP tools.
The skill catalog is dynamic — new skills are added regularly.
To find skills for a task:
- Call skills_searchSkills with a relevant query to find specific skills (e.g. "pdf", "image")
- Call skills_listSkills to browse all available skills
Then follow the execution workflow:
1. Call skills_listScripts on the skill slug to see available scripts
2. Call skills_runScript with reuseSession: true to execute
3. Read output via skills_readFile, then close the session with skills_closeSession
NEVER guess skill slugs or script names — always discover via searchSkills or listSkills first.
Always use reuseSession: true and read output via skills_readFile.
Always close sessions with skills_closeSession when done.Tip
searchSkills when the user has a specific task in mind, and listSkills when you want to see the full catalog (e.g. at startup or to show the user what's available).Pattern 2: Startup Pre-loading
Call listSkills once when your agent starts. Cache the results and inject them into the system prompt dynamically. This gives your agent a snapshot of the current catalog without hardcoding anything.
// On agent startup — run once, cache for the session
const { results } = await mcpClient.callTool("skills_listSkills", {});
const skillList = results
.map((s) => `- ${s.slug}: ${s.description} (${s.hasScripts ? "has scripts" : "template-based"})`)
.join("\n");
const systemPrompt = `You have access to SkillzDrive skills via MCP.
Available skills:
${skillList}
When the user asks for help with these tasks, use the appropriate skill.
Always call skills_listScripts before skills_runScript.`;Pattern 3: 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 4: 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.