skills-over-mcp-demo
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@skills-over-mcp-demoList the available skills."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
skills-over-mcp-demo
Demo MCP server that serves Agent Skills over MCP per SEP-2640 v1 (Skills Extension), built on the v2 TypeScript SDK (@modelcontextprotocol/server) and the experimental skills extension SDK (@olaservo/ext-skills).
Quickstart
npm install
npm run smoke # build + end-to-end client checks over stdio
npm run smoke:http # same checks over streamable HTTP (the transport OpenAI's importer uses)Both smoke tests connect with versionNegotiation: { mode: "auto" } and assert the connection lands on the latest protocol revision (2026-07-28) and that skills/list carries the SEP-2549 caching attributes, which the SEP scopes to that revision.
Or run the server directly for use from a host:
npm run build
node dist/index.js # stdio, serves the bundled skills/ directory
node dist/index.js path/to/dir # stdio, different skills directory
node dist/http.js --port 3000 # streamable HTTP at http://127.0.0.1:3000/mcpClaude Desktop / generic stdio host config:
{
"mcpServers": {
"skills-over-mcp-demo": {
"command": "node",
"args": ["<absolute path>/dist/index.js"]
}
}
}Related MCP server: Omni Skills
What it demonstrates
SEP-2640 surface | Where |
Capability declaration |
|
| 3 listed skills |
| the unlisted |
Partial listings + server |
|
|
|
| declared and implemented |
SEP-2549 list-caching attributes on |
|
Multi-segment skill paths |
|
Opt-in tools bridge ( |
|
Interop finding: ChatGPT connector creation fails against a tools-less MCP server — the "New Plugin" dialog errors out generically when tools/list returns -32601, even though the server is a valid SEP-2640 skills/resources server. The --tools-bridge flag exists for that case. It is off by default and not part of SEP-2640: the SEP defines no server-side tools (its reader-tool guidance is for host-provided tools), so the default surface stays pure-SEP. The flag mirrors that host-side reader tool server-side so tool-only hosts can consume the skills at all; the HF Space deployment enables it.
Skills served:
skill://dice-roller/tabletop-dice/SKILL.md multi-segment path, references/ supporting file
skill://mcp-glossary/SKILL.md single-file skill
skill://release-notes-writer/SKILL.md templates/ supporting file
skill://secret-menu/SKILL.md UNLISTED — reachable via skills/get + instructions pointer onlyThe smoke test (src/smoke.ts) exercises the client side of the SEP: capability gating, enumeration, unlisted-skill retrieval, digest + frontmatter verification on reads, unlisted-file rejection semantics, directory walking, and discoverAndBuildCatalog() producing a system-prompt catalog that merges the instructions-pointer skill with the listing.
Public endpoint (Hugging Face Space)
The server is deployed as a public Docker Space at olaservo/skills-over-mcp-demo:
https://olaservo-skills-over-mcp-demo.hf.space/mcpDeployment lives in hf-space/: assemble.ps1 stages a self-contained bundle (source + skills + Dockerfile + Space README) into hf-space/.staging, then hf upload olaservo/skills-over-mcp-demo hf-space/.staging . --repo-type space pushes it. Verify the live endpoint with tsx src/smoke-http.ts https://olaservo-skills-over-mcp-demo.hf.space/mcp. Free CPU Spaces sleep after inactivity; the first request after a sleep is slow.
Deployment note: the first push got auto-flagged by HF's abuse handler (rule "Cloudflare" — tunnel-domain strings in a source docstring). Removing the trycloudflare.com references and recreating the Space cleared it; keep tunnel hostnames out of Space content.
Testing the OpenAI skills import (Scan Tools)
OpenAI imports skills server-side: during plugin submission, the developer portal's Scan Tools connects to your MCP server over streamable HTTP, runs skills/list / skills/get / resources/read, verifies digests, and snapshots the skills into the plugin draft. Codex and ChatGPT then receive skills from OpenAI's plugin backend, not from your server. The test ladder:
Local validation with MCP Inspector (OpenAI's prescribed pre-submission check):
npm run start:http # terminal 1 npx @modelcontextprotocol/inspector # terminal 2 → Streamable HTTP → http://127.0.0.1:3000/mcp # or non-interactive: npx @modelcontextprotocol/inspector --cli http://127.0.0.1:3000/mcp --transport http --method resources/listExpose publicly — the deployed Hugging Face Space above is the stable public endpoint. (Alternative: a quick tunnel — start one against
http://localhost:3000, then restart the server with--allow-host <tunnel-hostname>.)Run Scan Tools in the OpenAI developer portal against
https://olaservo-skills-over-mcp-demo.hf.space/mcpduring plugin creation, then check the imported draft.
Result (2026-08-03): confirmed. Scan Tools imported all 3 listed skills with "Passed" validation; unlisted secret-menu did not import (the importer consumes only skills/list). Full findings — including the tools-surface requirement for ChatGPT connectors and the explicit-annotations validation — in docs/openai-plugin-submission.md. Expected: the 3 listed skills import with digests verified; secret-menu does not (their importer consumes only skills/list). Then exercise the plugin in ChatGPT developer mode.
The demo intentionally fits OpenAI's import limits (≤5 uniquely named skills, ≤100 files/skill, SKILL.md ≤256 KiB, files ≤1 MiB).
OpenAI skills import vs SEP-2640
OpenAI's MCP server plugin docs support importing skills from an MCP server, and their mechanism is recognizably SEP-2640 v1. Checked against the current SEP text (PR #2640, seps/2640-skills-extension.md):
Matches the SEP:
Capability declared at
capabilities.extensions["io.modelcontextprotocol/skills"]— OpenAI's docs even call out that the earlierexperimentallocation is wrong.skills/list(paginated vianextCursor) returninguri, verbatimfrontmatter(with requirednameanddescription), and a completeresourcesmanifest;skills/getfor single-entry retrieval; content fetched viaresources/read.Digest format
sha256:+ 64 lowercase hex chars; text resources hashed over the UTF-8 bytes ofcontent.text, blob resources hashed over the base64-decoded bytes — exactly the SEP's raw-bytes rule.Directory-name-equals-skill-name (the SEP's "final
<skill-path>segment MUST equalfrontmatter.name").Import-time verification that fetched content matches digests and that
SKILL.mdfrontmatter matches the catalog entry exactly — both host-side MUSTs in the SEP.Rejecting skills whose resources aren't all fetchable/digestible — the SEP says hosts MAY decline skills without a
resourcesmanifest, and OpenAI does.
Differences (host policy or stricter-than-SEP):
skill://treated as required. OpenAI says "use theskill://URI convention." The SEP says servers SHOULD useskill://but MAY serve skills under any scheme, and hosts MUST NOT infer skill-ness from the scheme. If OpenAI's scanner actually rejects non-skill://URIs, that's stricter than the SEP — a conformantgithub://…skills server would fail import. Practical takeaway: stick toskill://(as this demo does) for maximum compatibility.Import limits are OpenAI policy, not SEP. ≤5 uniquely named skills per scan, ≤10 catalog pages, ≤100 files per skill,
SKILL.md≤256 KiB, supporting files ≤1 MiB, ≤5 MiB per skill — none of these appear in the SEP. A conformant server can exceed them and simply won't import fully.Archives are OpenAI-internal. Their "generated archives per scan ≤8 MiB" limit refers to post-import packaging on their side. The SEP explicitly removed archive distribution from the wire protocol (see its Deferred Features appendix); no conflict, but worth knowing the archive never crosses the MCP connection.
Snapshot-only, listing-only. OpenAI imports at scan time and requires re-scanning to pick up changes — consistent with the SEP's point-in-time entries. But an import pipeline only consumes
skills/list, so SEP features aimed at live hosts don't apply: unlisted skills (like this demo'ssecret-menu), the instructions pointer, andresources/directory/readare invisible to OpenAI's importer. Servers targeting OpenAI import should list everything they want imported.
Layout
src/server.ts shared factory: loadSkills() + registerSkillResources()
src/index.ts stdio entry point (serveStdio)
src/http.ts streamable HTTP entry point (createMcpHandler + @modelcontextprotocol/node)
src/checks.ts shared SEP-2640 client-side checks
src/smoke.ts stdio smoke test
src/smoke-http.ts streamable HTTP smoke test
skills/ the demo skills (Agent Skills format: SKILL.md + supporting files)Maintenance
Related MCP Connectors
Search and discover Agent Skills from the skills.sh registry. Powered by HAPI MCP server.
Agent communication platform for agent to agent messaging via MCP. Messages, channels, skills.
Governed AI agent skills — one library, distributed to devs and exposed to remote agents over MCP.
- UnifAPIOAuthcom.unifapi
Hosted MCP server for live public-data APIs and Skills for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceAn MCP server that makes Agent Skills available to any MCP-compatible agent through a declarative, package.json-based configuration, enabling team-shareable skill management and execution.4MIT
- AlicenseNot gradedqualityAmaintenanceMCP server that unifies and synchronizes AI coding skills across multiple tools, exposing skill discovery and retrieval via list_skills and read_skill.43 npm13MIT
- AlicenseAqualityCmaintenanceMCP server that serves agent skills (SKILL.md bundles) to any MCP client, exposing them via tools and resources for tool-oriented and resource-aware clients.313 npmISC
- AlicenseNot gradedqualityCmaintenanceServes SKILL.md-based skills as MCP resources and tools over streamable HTTP, enabling remote discovery and retrieval of skill files with full YAML frontmatter parsing.Apache 2.0