localskills.sh provides a Model Context Protocol (MCP) server that lets AI agents discover, read, and author your teams’ skills without leaving their workflow. Any MCP client that supports Streamable HTTP with OAuth (Claude Code, claude.ai, Claude Desktop, Cursor, Codex CLI, Windsurf, VS Code, and others) can connect directly.
Server endpoint
The MCP server is available at:
https://localskills.sh/mcp/mcpIt uses the Streamable HTTP transport (stateless mode). Each request is independent; no session management is required.
Authentication
The MCP server requires OAuth 2.1. Unauthenticated requests receive a 401
with the standard WWW-Authenticate discovery hint, so well-behaved MCP
clients handle the whole flow automatically: they register dynamically, open a
browser authorization page, and receive a Bearer access token scoped to the MCP
resource.
During authorization you pick which of your organizations the connection is for. The token is bound to that organization: the agent sees and writes only that org’s skills. To work with a different organization, re-authenticate and pick it (most clients have a “reconnect” or “log out” action per server).
The server supports these OAuth scopes:
| Flag | Description |
|---|---|
| skills:read | Search skills and fetch their content (always granted) |
| skills:write | Create skills and publish versions (optional; uncheck it on the consent screen for a read-only connection) |
| offline_access | Refresh tokens, so the client stays connected without re-authorizing |
| openid / profile / email | Basic identity for the consent screen |
Discovery metadata lives at the standard well-known URLs:
https://localskills.sh/.well-known/oauth-authorization-server
https://localskills.sh/.well-known/oauth-protected-resource/mcp/mcpClient setup
Point any MCP client’s Streamable HTTP transport at
https://localskills.sh/mcp/mcp. The first connection triggers the browser
OAuth flow. Verified setups for common environments:
Claude Code
Add the server via the CLI (global):
claude mcp add localskills --transport http https://localskills.sh/mcp/mcpOr share it with your whole project by committing a .mcp.json at the repo
root:
{
"mcpServers": {
"localskills": {
"type": "http",
"url": "https://localskills.sh/mcp/mcp"
}
}
}Run /mcp inside a session to authenticate and inspect the connection.
claude.ai & Claude Desktop
Go to Settings → Connectors → Add custom connector and enter
https://localskills.sh/mcp/mcp. Approve the OAuth prompt and the tools become
available in chats (enable them from the search-and-tools menu). On
Team/Enterprise plans an admin may need to add the connector first.
Cursor
Add to .cursor/mcp.json in your project (or ~/.cursor/mcp.json globally):
{
"mcpServers": {
"localskills": {
"url": "https://localskills.sh/mcp/mcp"
}
}
}Codex CLI
Add to ~/.codex/config.toml:
[mcp_servers.localskills]
url = "https://localskills.sh/mcp/mcp"Then run codex mcp login localskills to complete the OAuth flow.
Windsurf
Add to ~/.codeium/windsurf/mcp_config.json (note the serverUrl key):
{
"mcpServers": {
"localskills": {
"serverUrl": "https://localskills.sh/mcp/mcp"
}
}
}VS Code (Copilot agent mode)
Add to .vscode/mcp.json in your workspace:
{
"servers": {
"localskills": {
"type": "http",
"url": "https://localskills.sh/mcp/mcp"
}
}
}Cline
Add to ~/.cline/data/settings/cline_mcp_settings.json:
{
"mcpServers": {
"localskills": {
"type": "streamableHttp",
"url": "https://localskills.sh/mcp/mcp"
}
}
}opencode
Add to opencode.json in your project (or
~/.config/opencode/opencode.json globally):
{
"mcp": {
"localskills": {
"type": "remote",
"url": "https://localskills.sh/mcp/mcp",
"enabled": true
}
}
}Available tools
The server exposes up to nine tools (create_upload_ticket registers only when
UPLOAD_SIGN_SECRET is configured on the worker). Skill and folder read tools
require the skills:read scope; whoami requires only an authenticated token,
not a skills scope. Write tools require skills:write and are not registered
at all on read-only connections.
whoami
Returns the identity behind the token: user id, email, granted scopes, and your
teams (each with an id, slug, name, and role). When the token is bound to one
organization, boundTeamId identifies it. Takes no arguments. Agents call it
first to learn which team values to pass to the tools below.
search_skills
Search skills and rules visible to you. Returns matching skills with their
slug, publicId, description, and current version; pass one to
get_skill_content to load it. Use scope: "personal" to search only managed
personal workspaces across your teams. The public catalog is not searchable
over MCP.
| Flag | Description |
|---|---|
| query | Search text to match against name, description, and tags |
| type | Filter by “skill” or “rule” |
| tag | Filter by a specific tag |
| team | Limit to one of your teams (tenant slug or id, from whoami) |
| folder | Limit to a folder subtree, e.g. “backend/database”; requires team |
| scope | all (default readable union), team (requires team and excludes managed personal workspaces), mine (skills you created), or personal (your managed personal workspace subtrees) |
| limit | Max results, 1–50 (default 20) |
get_skill_content
Load a skill’s full content. Returns the SKILL.md body plus any additional
package files: text files inlined up to a size budget, binaries listed as
metadata with a signed downloadUrl (see
bundled files). Multi-file packages also
include a signed packageDownloadUrl for the whole zip.
| Flag | Description |
|---|---|
| slug | The skill slug, or its publicId when the slug is ambiguous (required) |
| version | Version: exact semver (1.2.3), range (^1.0.0), or integer |
get_skill_file
Fetch one file from a skill’s package by path (for binary files that
get_skill_content lists as metadata only). Returns the bytes as base64
(chunked, 32 KiB by default, up to 1 MiB per call) plus a signed downloadUrl
that streams the whole file in one HTTP GET. Includes a SHA-256 checksum when
the file is returned whole.
| Flag | Description |
|---|---|
| slug | The skill slug, or its publicId (required) |
| path | File path inside the package, as listed by get_skill_content (required) |
| version | Version: exact semver, range, or integer |
| offset | Byte offset for chunked reads (default 0) |
| length | Max bytes to return (default 32 KiB, hard cap 1 MiB) |
list_folders
Browse a team’s folder tree (only paths you can read). Pass a returned path as
the folder argument to search_skills to scope a search.
| Flag | Description |
|---|---|
| team | Tenant slug or id, from whoami or search results (required) |
get_folder_access
Who can read a folder: every team member with access, resolved live from the
folder ACLs (direct grants, team grants, and admin-bypass roles), plus the
underlying grant list. Open folders report all members as access: "open".
Readable by anyone who can read the folder; editing ACLs stays on the website.
| Flag | Description |
|---|---|
| team | Tenant slug or id, from whoami or search results (required) |
| folder | Folder path (e.g. “individual/jane-doe”) or folder ID (required) |
create_skill
Create a new skill. Requires the skills:write scope and skill-creation
permission in the target organization. Idempotent on content: retrying an
identical create after a lost response returns the existing skill with
idempotent: true instead of creating a duplicate.
| Flag | Description |
|---|---|
| name | Skill name, 1–100 characters (required) |
| content | The root SKILL.md body in markdown (required unless uploadId is passed) |
| files | Supporting package files [{ path, content, encoding? }]; utf8 by default, base64 for binaries; max 100 files / 10 MB per call |
| uploadId | Commit a package staged via create_upload_ticket (up to 100 MB); mutually exclusive with content/files |
| tenantId | Team ID to create the skill under (required) |
| type | “skill” or “rule” (default: skill) |
| visibility | “public”, “private”, or “unlisted” (default: private) |
| tags | Up to 10 tags |
| description | Short description |
| folder | Existing folder path (e.g. “backend/database”) or folder ID (default: tenant root) |
| onConflict | “suffix” (default) auto-renames the slug when the name is taken; “error” fails with E_CONFLICT naming the existing skill instead of creating a renamed sibling |
create_upload_ticket
Stage a full-size package (up to 100 MB / 500 files) when the inline files
cap is too small. Returns a fileUrlTemplate (PUT each raw file, substituting
{path} URL-encoded per segment), a finalizeUrl (POST once all files are
uploaded; the server assembles the canonical deterministic zip), and the
uploadId to pass to create_skill / publish_version. Requires HTTP egress
and the skills:write scope; no parameters. Clients never build zip archives;
packaging is server-side.
publish_version
Publish a new version of an existing skill. Requires the skills:write scope.
Auto-bumps the patch version by default, or you can specify an explicit semver
or bump type. Idempotent on content: publishing bytes identical to the current
version (without a higher explicit semver) returns the current version with
idempotent: true.
| Flag | Description |
|---|---|
| slug | Skill slug (required) |
| content | The new root SKILL.md body for this version (required unless uploadId is passed) |
| files | Supporting package files [{ path, content, encoding? }]; utf8 by default, base64 for binaries; max 100 files / 10 MB per call |
| uploadId | Commit a package staged via create_upload_ticket (up to 100 MB); mutually exclusive with content/files |
| semver | Explicit semver (must be greater than current) |
| bump | Auto-bump: “major”, “minor”, or “patch” (default: patch) |
| message | Version message / changelog |
Resources
The server also provides MCP resources for browsing skills:
localskills://skills: Lists all skills your token can read, with metadata
(slug, name, description, type, semver).
localskills://skills/{slug}: Returns the SKILL.md content of one skill.
Agents can browse the list, then read individual skills to inject content into
their context.
localskills://skills/{slug}/files/{path}: Reads one file from a skill’s
package (current version). Binary files come back as base64 blob contents;
files over 1 MiB must be fetched with get_skill_file instead.
Bundled files & signed downloads
Skills are packages: a root SKILL.md plus optional supporting files (scripts, templates, binary assets). Agents have two ways to materialize those files:
Signed download URLs: get_skill_content and get_skill_file include a
downloadUrl on every non-inlined file (and a packageDownloadUrl for the
whole zip). These are HMAC-signed URLs, valid for 1 hour, minted only after the
caller’s access checks pass. One curl -o file '<url>' streams the file at any
size without passing bytes through model context. It’s the best path whenever
the agent’s sandbox has HTTP egress.
Inline base64: the guaranteed fallback for sandboxes without network access
(MCP calls ride the client’s connection, so they always work). Call
get_skill_file repeatedly, advancing offset by bytesReturned until eof,
then concatenate and decode the chunks.
Error handling
Tool failures set isError and carry a machine-readable code in
structuredContent.error.code:
| Flag | Description |
|---|---|
| E_NOT_FOUND | No such skill, team, folder, or file (or no access to it) |
| E_AMBIGUOUS | Slug matches several skills; retry with the publicId |
| E_ACCESS_DENIED | Authenticated but not allowed (missing membership or folder grant) |
| E_INVALID_INPUT | Bad arguments, e.g. folder without team |
Dynamic skill loading
Agents can discover and load skills on the fly during a conversation. When an agent encounters a task it doesn’t have instructions for, it can search your team’s library, pull in the relevant skill, and continue without interruption.
Example workflow: an agent is asked to write a Next.js API route. It searches for relevant skills, finds one with best practices, and injects it into context:
// 1. Agent calls search_skills
search_skills({ query: "next.js api routes", type: "skill", limit: 5 })
// 2. Agent picks the best match and fetches its content
get_skill_content({ slug: "nextjs-api-patterns" })
// 3. The skill content is now in the agent's context
// and it follows the instructions while writing codeBecause MCP tools are native to the agent’s runtime, this happens seamlessly. The agent decides when to search, what to load, and how to apply the instructions, with no manual intervention.
Loading skills on boot
To load skills from localskills.sh automatically when a session starts, add
instructions to your project’s agent configuration file: AGENTS.md,
CLAUDE.md, .cursorrules, or equivalent.
CLAUDE.md example: add this to your project’s CLAUDE.md so Claude Code
loads skills at the start of every session:
# Skills
At the start of each session, use the localskills MCP server to load
the following skills into context:
- `nextjs-api-patterns`: Follow these patterns for all API routes
- `drizzle-d1-guide`: Reference for database queries
- `testing-conventions`: Standards for writing tests
To load a skill, call get_skill_content with the slug above.
If you need additional skills for a task, search localskills.sh first.AGENTS.md example: for multi-agent setups, scope skills to specific agent roles:
# Agent Skills
## All agents
Load these skills from localskills.sh via MCP at session start:
- `code-review-checklist`: Apply during all code reviews
- `security-rules`: Enforce on every change
## Frontend agent
Additionally load:
- `react-component-patterns`: Component architecture guidelines
- `tailwind-conventions`: Styling standards
## Backend agent
Additionally load:
- `api-design-guide`: REST API conventions
- `error-handling-patterns`: Error handling standards.cursorrules example: add MCP skill loading to your Cursor project rules:
You have access to the localskills MCP server.
At the start of each conversation, load these skills:
1. Call get_skill_content({ slug: "react-component-patterns" })
2. Call get_skill_content({ slug: "typescript-strict-mode" })
Follow the loaded skill instructions for all code you write.
When asked about an unfamiliar topic, search localskills.sh
for relevant skills before answering.This pattern gives teams shared coding standards and guidelines that every agent session picks up automatically. Update a skill on localskills.sh and every agent gets the latest version on its next session (no reinstall needed).
Permissions & access
MCP requests act as the user who authorized the connection, within the
organization chosen during authorization. The server surfaces only your teams’
skills; the public catalog is browsable on the website and REST API, not over
MCP. Folder restrictions apply exactly as they do in the dashboard: skills in
folders you have no grant for don’t appear in search, resources, or reads.
Writes (create_skill, publish_version) additionally require the
corresponding skill permissions in the target organization.
Revoking access works as you’d expect: leave (or be removed from) an organization and existing tokens bound to it stop returning its skills immediately.
Health check
Verify the server is running:
curl https://localskills.sh/mcp/healthReturns {"status":"ok"} when healthy.