Generate Skills from HTTP MCP servers with async job patterns (submit/status/result). Use when converting MCP specifications (.mcp.json) into reusable Skills using mcp_tool_catalog.yaml...
Generate reusable Skills from HTTP MCP servers that use async job patterns.
.mcp.json into a packaged Skill (tool info is fetched from catalog)Many MCPs require URL inputs for media files. Use fal_client to upload local files:
# Upload file and get URL (one-liner)
python -c "import fal_client; url=fal_client.upload_file(r'/path/to/file.png'); print(f'URL: {url}')"
# Examples for different platforms:
# Windows
python -c "import fal_client; url=fal_client.upload_file(r'C:\Users\name\image.png'); print(f'URL: {url}')"
# Linux/Mac
python -c "import fal_client; url=fal_client.upload_file('/home/user/image.png'); print(f'URL: {url}')"
# Android (Termux)
python -c "import fal_client; url=fal_client.upload_file('/storage/emulated/0/Download/image.png'); print(f'URL: {url}')"
The returned URL (e.g., https://v3b.fal.media/files/...) can be used in image_url, image_urls, audio_url, etc. parameters.
Supported formats: png, jpg, jpeg, gif, webp, mp3, wav, mp4, webm, etc.
Tool information is automatically fetched from mcp_tool_catalog.yaml:
# Generate skills for ALL servers in mcp.json
python scripts/generate_skill.py \
--mcp-config /path/to/.mcp.json
# Generate skill for specific server(s) only
python scripts/generate_skill.py \
--mcp-config /path/to/.mcp.json \
-s fal-ai/flux-lora
# Generate multiple specific servers
python scripts/generate_skill.py \
--mcp-config /path/to/.mcp.json \
-s server1 -s server2
Output: .claude/skills/<skill-name>/SKILL.md
The server name in .mcp.json is used to look up tools from the catalog.
For MCPs with many tools, use --lazy to minimize initial context consumption:
python scripts/generate_skill.py \
--mcp-config /path/to/.mcp.json \
--lazy
In lazy mode:
references/tools/<skill>.yamlIf you have a local tools.info file:
python scripts/generate_skill.py \
--mcp-config /path/to/.mcp.json \
--tools-info /path/to/tools.info \
--name my-mcp-skill
python scripts/generate_skill.py \
--mcp-config /path/to/.mcp.json \
--output /custom/path
python scripts/mcp_async_call.py \
--endpoint "https://mcp.example.com/sse" \
--submit-tool "generate_image" \
--status-tool "check_status" \
--result-tool "get_result" \
--args '{"prompt": "a cat"}' \
--output ./output
1. SUBMIT ā POST JSON-RPC ā Get session_id
2. STATUS ā Poll with session_id ā Wait for "completed"
3. RESULT ā Get download URL
4. DOWNLOAD ā Save file locally
All MCP calls use this structure:
{
"jsonrpc": "2.0",
"id": "unique-id",
"method": "tools/call",
"params": {
"name": "tool_name",
"arguments": { "key": "value" }
}
}
Multi-server format (recommended):
{
"mcpServers": {
"fal-ai/flux-lora": {
"url": "https://mcp.example.com/flux-lora/sse",
"headers": {
"Authorization": "Bearer xxx"
}
},
"fal-ai/video-enhance": {
"url": "https://mcp.example.com/video-enhance/sse",
"headers": {
"Authorization": "Bearer xxx"
}
}
}
}
With multi-server format:
python generate_skill.py -m mcp.json ā Generates skills for ALL serverspython generate_skill.py -m mcp.json -s fal-ai/flux-lora ā Generates only specified serverpython generate_skill.py -m mcp.json -s server1 -s server2 ā Multiple serversSingle-server format:
{
"name": "t2i-kamui-fal-flux-lora",
"url": "https://kamui-code.ai/t2i/fal/flux-lora",
"auth_header": "KAMUI-CODE-PASS",
"auth_value": "your-pass"
}
Tool information is fetched from:
https://raw.githubusercontent.com/Yumeno/kamuicode-config-manager/main/mcp_tool_catalog.yaml
The catalog contains 266+ servers with tool definitions:
servers:
- id: t2i-kamui-fal-flux-lora
status: online
tools:
- name: flux_lora_submit
description: Submit Flux LoRA image generation request
inputSchema:
properties:
prompt:
description: Image prompt
type: string
required:
- prompt
type: object
Optional, for backward compatibility:
[
{
"name": "generate",
"description": "Generate content",
"inputSchema": {
"type": "object",
"properties": {
"prompt": { "type": "string", "description": "Input prompt" }
},
"required": ["prompt"]
}
}
]
scripts/mcp_async_call.pyMain async MCP caller with full flow automation.
Options:
--endpoint, -e: MCP server URL--submit-tool: Tool name for job submission--status-tool: Tool name for status checking--result-tool: Tool name for result retrieval--args, -a: Submit arguments as JSON string--args-file: Load arguments from JSON file--output, -o: Output directory (default: ./output)--output-file, -O: Output file path (overrides auto filename, allows overwrite)--auto-filename: Use {request_id}_{timestamp}.{ext} format--poll-interval: Seconds between polls (default: queue_config.yaml poll_interval)--max-polls: Maximum poll attempts (default: job_timeout / poll_interval)--header: Add custom header (format: Key:Value)--config, -c: Load endpoint from .mcp.json--save-logs: Save request/response logs to {output}/logs/--save-logs-inline: Save logs alongside output file as {filename}_*.jsonAsync jobs are processed through the queue daemon for concurrency and rate limiting.
Key settings (queue_config.yaml):
max_concurrent: Maximum concurrent jobsstart_interval: Minimum time between job starts (seconds)poll_interval: Status poll interval (seconds)job_timeout: Job timeout (seconds)client_idle_timeout: Client idle timeout (seconds, 0 disables)global_rate_per_min: Global rate limit per minuteglobal_burst: Global burstendpoint_rates: Per-endpoint rate limiting (optional)Notes:
--poll-interval/--max-polls are omitted, the daemon derives defaults from poll_interval and job_timeout.endpoint_rates is applied in addition to the global rate limit.File Extension Detection:
Extension is determined in this order:
--output-fileContent-Type header from download responseDuplicate File Avoidance:
When --output-file is not specified, existing files are not overwritten. A suffix is added:
output.png ā output_1.png ā output_2.pngscripts/generate_skill.pyGenerate complete Skill from MCP specifications.
Options:
--mcp-config, -m: Path to .mcp.json (required)--servers, -s: Server name(s) to generate (can specify multiple, default: all)--tools-info, -t: Path to tools.info (legacy mode, single server only)--output, -o: Output directory--name, -n: Skill name (auto-detected if omitted, single server only)--catalog-url: Custom catalog URL (default: GitHub raw URL)--lazy, -l: Generate minimal SKILL.md (tool definitions in references/tools/*.yaml)Requirements:
pip install pyyaml requests (for catalog fetching)Skills are generated to .claude/skills/<skill-name>/:
Normal mode:
.claude/skills/<skill-name>/
āāā SKILL.md # Usage documentation (full tool details)
āāā scripts/
ā āāā mcp_async_call.py # Core async caller
ā āāā skill_name.py # Convenience wrapper
āāā references/
āāā mcp.json # Original MCP config
āāā tools.json # Original tool specs
Lazy mode (--lazy):
.claude/skills/<skill-name>/
āāā SKILL.md # Usage documentation (minimal)
āāā scripts/
ā āāā mcp_async_call.py # Core async caller
ā āāā skill_name.py # Convenience wrapper
āāā references/
āāā mcp.json # Original MCP config
āāā tools/
āāā <skill-name>.yaml # Tool definitions + usage examples (YAML)
| Status | Meaning |
|---|---|
pending, queued |
Job waiting |
processing, running |
In progress |
completed, done, success |
Finished |
failed, error |
Failed |
from scripts.mcp_async_call import run_async_mcp_job
result = run_async_mcp_job(
endpoint="https://mcp.example.com/sse",
submit_tool="generate",
submit_args={"prompt": "sunset over mountains"},
status_tool="status",
result_tool="result",
output_dir="./output",
poll_interval=2.0,
max_polls=300,
)
print(result["saved_path"]) # Path to downloaded file
The script handles:
All errors raise exceptions with descriptive messages.