
OpenClaw QuickStart (6): Skills, MCP, and Shipping Something Real
Write a Skill, attach a Playwright MCP server, and ship a morning-briefing agent.
After five pieces, you have a working OpenClaw with a chat channel. This is where it stops being a demo.

What we’ll build#

A morning-briefing agent that:
- Runs at 7am every weekday
- Fetches the top headlines from Hacker News (via a Playwright MCP server)
- Reads my calendar for the day (via a Skill that wraps
gcalcli) - Summarizes both into a paragraph and pushes it to my Telegram
This is a real workflow. By the end, you’ll have the structure to swap in your own data sources. But first, let’s understand the two systems we’re combining.
Skills vs. Tools vs. MCP — the mental model#
These three words often get mixed up, but they shouldn’t.
| Concept | What it is | Who writes it | When it loads |
|---|---|---|---|
| Tool | A verb. Read file, exec command, web search. Has a typed schema and a handler function. | Framework author or you (custom tools) | Always loaded; the model sees the full tool list every turn |
| Skill | A noun-of-knowledge. A Markdown SOP that tells the agent how to accomplish a specific task. | You | Lazily — manifest only until triggered, then body is paged in |
| MCP Server | An external process that exposes additional tools via the Model Context Protocol. | Third-party or you | Loaded at gateway startup; tools appear alongside built-in tools |
The relationship: Skills use tools. MCP servers provide tools. A skill might say “use the Playwright tools to scrape this page” — the Playwright tools come from an MCP server, and the skill tells the agent what to do with them.
Think of it like this: Tools are the hands. Skills are the training manual. MCP is a way to give the agent more hands.
Step 1: Write a Skill#
A Skill lives at ~/.openclaw/skills/<name>/SKILL.md. Let’s write one for “summarize headlines”:
| |
Create ~/.openclaw/skills/summarize-headlines/SKILL.md:
| |
Anatomy of a SKILL.md#
The file has two sections: the YAML front matter (the manifest) and the Markdown body (the SOP). Both matter, and they do different things at different times.
The manifest is loaded at gateway startup. Every skill’s manifest is included in the system prompt so the model can decide which skill to invoke. The fields:
| Field | Required | Purpose | Example |
|---|---|---|---|
name | Yes | Unique identifier. Used in logs and cross-references. | summarize-headlines |
description | Yes | One-line summary. The model reads this to decide relevance. | Summarize a list of headlines... |
trigger | Yes | Natural-language clause. Write it from the user’s perspective, not the implementation’s. | when user asks for a news briefing |
tools_required | No | Which tools the skill needs. If listed, the gateway pre-authorizes them. | [web_search, exec] |
skills_required | No | Other skills this skill depends on. Their bodies are hot-loaded when this skill triggers. | [today-calendar] |
priority | No | high, normal, or low. Breaks ties when multiple skills match. Default: normal. | high |
version | No | Semver string. Informational only; helps when you share skills. | 1.0.0 |
The body is only loaded when the model triggers the skill. It is the SOP — the instructions, templates, edge cases, and output format. Treat it like an onboarding doc for a new employee. The more specific the better. Vague instructions (“summarize well”) produce vague results. Concrete instructions (“maximum 4 sentences, lead with highest-signal item, skip paywalled sources”) produce consistent output.
Writing effective triggers#
The trigger clause is the single most important line in a skill. If it is too broad, the skill fires when it should not. If it is too narrow, it never fires when it should. Some patterns:
Bad triggers:
when the user asks about news— too broad, will fire on “what’s new in the codebase”when summarize-headlines should run— circular, means nothing to the model
Good triggers:
when user asks for a news briefing, headline summary, or daily news digest— specific nounswhen user asks to take meeting notes or document a meeting— action + domain
Debugging trigger issues: If a skill is not firing, add OPENCLAW_LOG=debug to your environment and send a test message. Look for skill_selection in gateway.log — it shows which skills the model considered and why it picked (or didn’t pick) each one.
Restart the gateway and verify the skill loaded:
| |
You can also inspect what the model sees:
| |
Step 2: Attach an MCP server#
MCP — Model Context Protocol — is a standard for connecting LLMs to external tool servers. OpenClaw doesn’t speak MCP natively; it uses MCPorter as a shim that translates between OpenClaw’s internal tool format and the MCP protocol.
Installing MCPorter#
| |
Verify:
| |
Adding Playwright as an MCP server#
| |
This tells MCPorter: “there is an MCP server called playwright, and you start it by running npx @playwright/mcp@latest.” MCPorter will launch the process and manage its lifecycle.
Now tell OpenClaw about MCPorter in openclaw.json:
| |
Restart the gateway. The Playwright MCP server exposes browser-automation tools that the agent can now call. Here is what you get:
| MCP Tool | What it does | Typical use |
|---|---|---|
browser_navigate | Go to a URL | Opening a page to scrape |
browser_snapshot | Accessibility tree of current page | Reading structured content |
browser_click | Click an element | Navigating multi-page flows |
browser_type | Type into a field | Form filling, search boxes |
browser_evaluate | Run arbitrary JS on page | Extracting data the DOM tree misses |
browser_take_screenshot | Capture the viewport | Visual verification, debugging |
Testing the MCP connection#
From the TUI:
| |
If the agent comes back with a list, the wiring is good. If it fails, the most common issues are:
- MCPorter not running. Check
mcporter status— theplaywrightserver should showrunning. If it showsstopped, runmcporter start playwrightmanually and check~/.mcporter/logs/playwright.logfor errors. - Port conflict. MCPorter defaults to
:7890. If something else uses that port, setMCPORTER_PORT=7891and updateporter_endpointinopenclaw.json. - Playwright not installed. The first
npx @playwright/mcp@latestrun downloads browsers. This can take 2-3 minutes and ~400MB. If it was interrupted, runnpx playwright install chromiummanually.
Adding other MCP servers#
The same pattern works for any MCP-compliant server. Some useful ones:
| |
After adding, update openclaw.json:
| |
Each server’s tools appear in the agent’s tool list alongside built-in tools. The model treats them identically.
Step 3: A skill that wraps a CLI tool#
Not every integration needs an MCP server. For simple CLI tools, a skill that uses the exec tool is often easier. I use gcalcli for Google Calendar:
| |
~/.openclaw/skills/today-calendar/SKILL.md:
| |
Notice the skill is essentially a recipe, not a function. The model is the runtime. The exec tool is the verb. The skill is the noun-of-knowledge that ties them together.
When to use exec vs. MCP#
The decision is straightforward:
| Scenario | Use exec | Use MCP |
|---|---|---|
| One-shot CLI command | Yes | Overkill |
| Stateful interaction (browser, database) | No | Yes |
| Tool with complex typed output | Maybe | Preferred |
| Tool you want to share across projects | No | Yes |
| Quick prototype | Yes | No |
The rule of thumb: if the interaction is “run a command, parse stdout,” use exec. If the interaction involves multiple back-and-forth steps or persistent state, use an MCP server.
Security considerations for exec-based skills#
The exec tool has dangerous permission level for a reason. When a skill uses exec, consider:
- Pin the command. Write the exact command in the skill body, not “run whatever shell command is needed.” The model will sometimes improvise if given room.
- Use
trusted_commandsin config. Add the specific commands your skill uses to the trusted list so the user does not get a confirmation prompt every time:1 2 3 4 5"tools": { "exec": { "trusted_commands": ["gcalcli agenda", "gcalcli list", "git status"] } } - Validate output. If the skill processes tool output and feeds it back to the model, consider what happens if the command returns unexpected content. A malicious calendar event title could theoretically inject instructions.
Step 4: A composing skill#

This is where skills become powerful. A composing skill orchestrates other skills and tools into a multi-step workflow:
| |
~/.openclaw/skills/morning-briefing/SKILL.md:
| |
Morning Briefing — YYYY-MM-DD#
Today#
[output of today-calendar]
News#
[output of summarize-headlines]
| |
The skills_required field tells OpenClaw to keep the bodies of those skills hot-loaded when this skill triggers. No re-fetch, no extra latency. This is an important optimization — without it, the agent would need to trigger each sub-skill individually, paying the manifest-lookup cost each time.
How skill composition works internally#
When the morning-briefing skill triggers, the gateway does the following:
- Loads the morning-briefing body into the prompt.
- Sees
skills_required: [today-calendar, summarize-headlines]. - Loads both sub-skill bodies into the prompt alongside the parent.
- The model now has all three SOPs and can execute steps sequentially.
The agent loop runs normally — the model plans tool calls, the gateway executes them, results come back. The difference is that the model has more context about how to use each tool because all three skill bodies are present.
This is different from function composition in code. There is no call stack, no return value. The model reads all three SOPs, internalizes them, and executes the combined plan. It works because language models are good at following multi-step instructions.
Debugging composing skills#
The most common failure: the model skips a step. It fetches the news but forgets the calendar, or vice versa. This happens when the prompt is too long and the model loses track.
To diagnose, check the turn-by-turn JSON dump:
| |
If you see browser_navigate but no exec (for gcalcli), the model skipped the calendar step. Fixes:
- Number your steps explicitly (the example above does this).
- Add a checklist at the end of the skill body: “Before sending, verify: calendar section present? news section present? Date correct?”
- Lower
max_turnsfor this skill if it tends to spiral. Inopenclaw.json:1 2 3 4 5"skill_config": { "morning-briefing": { "max_turns": 15 } }
Step 5: Cron#
Skills become truly useful when they run without you. In openclaw.json:
| |
0 7 * * 1-5 is 7am Mon-Fri. Restart the gateway. Verify with:
| |
The first time it runs, watch the gateway log. You will see the agent loop fire, the skill load, the Playwright tool calls scroll past, and finally a message land in your Telegram.
Cron configuration reference#
| Field | Required | Type | Description |
|---|---|---|---|
name | Yes | string | Unique job name. Used in logs and openclaw cron list. |
schedule | Yes | cron expr | Standard 5-field cron expression. |
skill | Yes | string | Skill name to trigger. Must exist in ~/.openclaw/skills/. |
channel | Yes | string | Where to send output. Must be a configured channel. |
user_id | No | string | Which user’s memory/context to use. Default: the admin user. |
timeout_sec | No | integer | Maximum execution time. Default: 120. |
retry | No | integer | Number of retries on failure. Default: 0. |
env | No | object | Extra environment variables passed to tools during this job. |
What breaks with cron#
The agent loop runs in a synthetic session — there is no real user on the other end. This has two consequences:
- No confirmation prompts. If the skill uses
execand the command is not intrusted_commands, the cron job hangs waiting for confirmation that never comes. Always add cron-triggered commands to the trusted list. - No follow-up. If the model’s response includes a question (“Should I include crypto news?”), nobody answers. The message posts to the channel and the session ends. Design cron-triggered skills to be self-contained — all decisions should be in the SOP, not left to user interaction.
A useful pattern for cron debugging:
| |
Real-world skill examples#
The morning-briefing is a starter project. Here are three more patterns I use, with their key design choices.
Pattern 1: Git changelog#
A skill that generates a weekly changelog from git commits:
| |
Why this works: the skill has a clear input (git log), a clear transformation (grouping by prefix), and a clear output (markdown file). No ambiguity.
Pattern 2: Database health check#
A skill using an SQLite MCP server for periodic checks:
| |
Pattern 3: PR review assistant#
A skill combining GitHub MCP with code analysis:
| |
Troubleshooting#
Here are the problems I hit in my first month, and how I fixed them.
Skill fires but produces wrong output#
Symptom: The skill triggers correctly, but the agent ignores half the SOP instructions.
Cause: The skill body is too long or too vague. Models skim long instructions just like humans do.
Fix: Keep the body under 500 words. Use numbered steps, not prose. Put the output template last (recency bias helps). If the skill must be complex, split it into sub-skills with skills_required.
MCP server crashes mid-conversation#
Symptom: The agent gets a tool error “connection refused” partway through a workflow.
Cause: The MCP server process exited. Playwright in particular crashes if the browser encounters an out-of-memory page or a download dialog it cannot handle.
Fix: MCPorter has auto-restart. Verify it is enabled:
| |
If the server crashes more than max_restarts times in 60 seconds, MCPorter gives up and logs an error. Check ~/.mcporter/logs/playwright.log for the crash reason. Common culprits: pages that trigger infinite JS loops, or sites that serve 100MB+ resources.
Cron job runs but sends nothing#
Symptom: openclaw cron history shows the job ran successfully, but no message appeared in the channel.
Cause: Usually a channel authentication issue. OAuth tokens expire, DingTalk webhook URLs rotate, Telegram bot tokens get revoked.
Fix: Check gateway.log for the cron run timestamp. Look for “channel send failed” errors. Re-authenticate the channel: openclaw channel test telegram sends a test message and reports any auth errors.
Two skills fight over the same trigger#
Symptom: Inconsistent behavior — sometimes skill A fires, sometimes skill B, for the same user message.
Cause: Overlapping trigger clauses. The model picks one based on subtle phrasing differences.
Fix: Make triggers mutually exclusive. If you have both a “meeting notes” and a “project notes” skill, do not write when user asks about notes for either. Use when user asks about meeting notes or documenting a meeting and when user asks about project notes or project status.
You can also force a specific skill:
| |
This bypasses trigger matching entirely.
What you have now#
- A long-lived agent talking to a real chat platform
- Skills that capture domain knowledge separately from the agent loop
- An MCP server providing capabilities OpenClaw doesn’t have natively
- A cron job that turns it from “I have to ask” into “it shows up”
- The debugging tools to figure out what went wrong when it does
That is the whole loop. Every other case study in the official docs — second-brain, content pipeline, devops automation — is a variation on these five steps. Different skills, different MCPs, different cron lines.
What I’d build next#
Three things, in order of effort:
Add a feedback loop. Reply to the morning briefing with corrections (“skip crypto headlines”). Have a skill that writes those corrections into
~/.openclaw/memory/feedback/morning-briefing.md. The next morning’s briefing pulls them in via ContextEngine retrieval. After a week, the briefing silently adapts to your preferences without you touching the SOP.Make the news source configurable. A skill that reads from
~/openclaw-workspace/sources.yamland iterates over a list of URLs. That gets you “RSS reader as agent” almost for free. The YAML file becomes a simple UI — add a URL, get it in tomorrow’s briefing.Wire a second channel. Same agent, also on DingTalk for work hours. The skills don’t change — the channel layer is decoupled. You get the same morning briefing in both places, or route different skills to different channels based on context.
That is where I will leave the QuickStart. The rest of the official docs go deep on each layer; you now have the map to navigate them.
If you want a single takeaway, it is that the boring layers — skills, memory, channels — are where the value is. The agent loop is the same agent loop everyone has. What makes your install useful is the skill library you build and the channels you put it on. Good luck.
OpenClaw QuickStart 10 parts
- 01 OpenClaw QuickStart (1): What This Thing Actually Is
- 02 OpenClaw QuickStart (2): Install and First Chat in 10 Minutes
- 03 OpenClaw QuickStart (3): The Six Layers That Make the Agent Loop Work
- 04 OpenClaw QuickStart (4): Configuration, Model Providers, and the Coding Plan Trick
- 05 OpenClaw QuickStart (5): Wiring Telegram, DingTalk, and the WeChat Reality
- 06 OpenClaw QuickStart (6): Skills, MCP, and Shipping Something Real you are here
- 07 OpenClaw QuickStart (7): The Memory System, Without the Magic
- 08 OpenClaw QuickStart (8): Heartbeat, Cron, and Getting Pinged at 7am
- 09 OpenClaw QuickStart (9): The China IM Picker, with Honest Tradeoffs
- 10 OpenClaw QuickStart (10): Production Deploy and the Failure Modes Nobody Warns You About