Drop a skills/ and prompts/ folder, get a FastMCP server with a browseable catalog UI.
Project description
Drop MCP
Drop a skills/ and prompts/ folder, get a FastMCP
server — with a browseable catalog — in one line.
import dropmcp
dropmcp.run(skills="skills", prompts="prompts")
dropmcp is the reusable, repo-agnostic engine behind several internal
skills/prompts MCP servers, extracted as a standalone library.
Why dropmcp?
Skills and prompts are just markdown — anyone can write them, and there are
plenty of ways to get them in front of an agent: copy them into .cursor/skills,
ship an IDE plugin, sync a folder, paste them into context. The trouble is that
every one of those is tied to a single tool, has no central updates, no way to
scope who sees what, and no signal about what actually gets used. Spread across
many people, repos, and editors, that fragments fast — the same skill forked
five ways with no canonical copy, and skills that work in one agent but not the
next.
Serving skills over MCP solves the delivery problem generically: one server is reachable from any MCP client (Cursor, Claude Code, CI, whatever comes next), the filesystem stays the single source of truth so there's no registry to drift, and because every skill call is one request, usage is observable for free. The catch is that standing up that server is the same boilerplate every time — frontmatter parsing, tool/prompt/resource registration, a browseable catalog, telemetry, hosting.
dropmcp is that boilerplate, extracted and built around Fast MCP. Point it at a skills/ and prompts/
folder and you get a tested, observable MCP server, so you run one focused
server per audience instead of rebuilding the engine each time. Authors maintain
content, not infrastructure.
Install
pip install dropmcp
Optional OpenTelemetry export:
pip install "dropmcp[otel]"
Quick start
Lay out your content:
skills/
my-skill/
SKILL.md # YAML frontmatter: name, category, description
reference.md # optional supporting files -> resource links
prompts/
my-prompt/
PROMPT.md # YAML frontmatter: name, description, arguments
assets/ # optional assets -> prompt://my-prompt/assets/<file>
Then serve it over streamable-HTTP:
import dropmcp
dropmcp.run(skills="skills", prompts="prompts") # binds 127.0.0.1:8000
dropmcp.run(skills="skills", prompts="prompts", host="0.0.0.0", port=8000)
dropmcp is a hosted server — it exists to share skills and prompts with
remote MCP clients, so it serves over streamable-HTTP only (no local stdio).
The catalog UI is at http://<host>:<port>/ and the MCP endpoint at /mcp.
Need to customise the server before it runs? Use the factory:
mcp = dropmcp.create_server(skills="skills", prompts="prompts")
# add your own routes / middleware ...
mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)
A runnable example lives in examples/.
Scaffold a new server (copier)
Generate a ready-to-run project from the bundled template:
pip install copier
copier copy gh:agoda-com/dropmcp//template my-skills-mcp
cd my-skills-mcp
pip install -r requirements.txt
python server.py
The template asks for a project name and whether to include Promptfoo eval scaffolding under tests/.
Configuration
Every option can be passed as a keyword argument, set via a DROPMCP_*
environment variable, or left to its default (kwargs win, then env, then
default).
| kwarg | env | default | purpose |
|---|---|---|---|
skills |
DROPMCP_SKILLS |
skills |
skills directory |
prompts |
DROPMCP_PROMPTS |
prompts |
prompts directory |
name |
DROPMCP_NAME |
dropmcp |
server name shown to clients |
website_url |
DROPMCP_WEBSITE_URL |
– | server homepage URL |
icon |
DROPMCP_ICON |
– | path to an icon (svg/png) |
instructions |
DROPMCP_INSTRUCTIONS |
auto | INSTRUCTIONS.md template |
host |
DROPMCP_HOST |
127.0.0.1 |
bind host |
port |
DROPMCP_PORT |
8000 |
bind port |
ui_enabled |
DROPMCP_UI |
true |
serve the catalog HTTP routes |
feedback_enabled |
DROPMCP_FEEDBACK |
true |
enable the record_feedback tool, feedback HTTP routes, and always-on instructions |
reload |
DROPMCP_RELOAD |
false |
re-scan skills/prompts on every request |
database_url |
DROPMCP_DATABASE_URL |
sqlite:///<cwd>/dropmcp.db |
feedback database (SQLite file or Postgres URL) |
If an INSTRUCTIONS.md sits next to your content folders it is picked up
automatically; otherwise a generic default ships with the package. The
{{INSTRUCTION_SUMMARIES}} and {{PROMPT_SUMMARIES}} placeholders are
filled from each item's instruction_summary frontmatter.
Hosting guide
dropmcp serves over streamable-HTTP for multi-client hosted deployments. Run
your server.py:
DROPMCP_HOST=0.0.0.0 DROPMCP_PORT=8000 python server.py
The catalog UI is available at http://localhost:8000/, the health check
endpoint at http://localhost:8000/health, and the MCP endpoint at
http://localhost:8000/mcp. Point your remote MCP clients there.
Docker
A minimal Dockerfile for a hosted deployment:
FROM python:3.12-slim
WORKDIR /app
RUN pip install dropmcp
COPY skills/ skills/
COPY prompts/ prompts/
COPY INSTRUCTIONS.md . # optional
ENV DROPMCP_HOST=0.0.0.0
ENV DROPMCP_PORT=8000
ENV DROPMCP_NAME="My Skills MCP"
EXPOSE 8000
CMD ["python", "-m", "dropmcp"]
Build and run:
docker build -t my-skills-mcp .
docker run -p 8000:8000 my-skills-mcp
Connect a remote MCP client to http://<host>:8000/mcp.
Environment-only deployment
All settings can be passed via environment variables and started with
python -m dropmcp — no server.py needed:
export DROPMCP_SKILLS=/data/skills
export DROPMCP_PROMPTS=/data/prompts
export DROPMCP_HOST=0.0.0.0
export DROPMCP_PORT=8000
export DROPMCP_NAME="Acme Skills"
export DROPMCP_WEBSITE_URL="https://skills.example.com"
python -m dropmcp
OpenTelemetry
Install the OTEL extra and point at your collector:
pip install "dropmcp[otel]"
export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-collector:4318"
python -m dropmcp
Metrics and structured logs are emitted per skill invocation, prompt render,
and resource read. When OTEL_EXPORTER_OTLP_ENDPOINT is unset (the default),
telemetry is a no-op — no extra imports, no overhead.
Agent feedback
dropmcp includes a built-in feedback loop for when agents get corrected:
record_feedbackMCP tool — agents write structured feedback (no external Slack/GitLab wiring).- SQLite by default — a
dropmcp.dbfile is created next to your content folders on first run. - Postgres override — set
DROPMCP_DATABASE_URL=postgresql://user:pass@host/dbfor durable hosted storage. - Feedback UI — browse, search, filter, and triage at
/feedbackin the catalog SPA (GET/PATCH /api/feedback).
Privacy guardrails: no verbatim user prompts, code, secrets, or PII. When feedback
is enabled, dropmcp injects always-on guidance into the server instructions
describing when and how agents should call record_feedback — no separate skill
to install. Disable the whole feature (tool, HTTP routes, and instructions) with
DROPMCP_FEEDBACK=false.
In containers, mount a volume over the SQLite file (or use Postgres) or feedback is lost when the pod restarts.
Skill and prompt format
SKILL.md
---
name: my-skill
category: my-category
description: One-line description shown to the LLM as the tool description.
instruction_summary: Short phrase for the server-level INSTRUCTIONS.md bullet.
---
Full skill body here — this is what the LLM receives when it calls the tool.
PROMPT.md
---
name: my-prompt
description: Short description shown in the catalog.
instruction_summary: Short phrase for INSTRUCTIONS.md.
arguments:
- name: who
description: The person to greet.
required: true
- name: tone
description: Greeting tone (optional).
required: false
---
Write a {{tone}} greeting addressed to {{who}}.
Validate your content before starting the server with the bundled checker:
python -c "import sys; from dropmcp.validate import run_validation; sys.exit(run_validation('skills', 'prompts'))"
Releasing
Releases are cut by pushing a v* git tag. The CI workflow
does the rest: on a tag it builds the catalog UI, builds the wheel + sdist,
publishes to PyPI via trusted publishing
(no API token needed), and creates a GitHub Release with auto-generated notes.
To ship a new version:
-
Bump the version in both
pyproject.toml(version) andsrc/dropmcp/__init__.py(__version__) — they must match, and the tag must match too. Use semver. -
Land the bump on
mainvia a merged PR (CI runs tests + the UI build on the PR). -
Tag the merge commit and push the tag:
git checkout main && git pull git tag v0.2.0 git push origin v0.2.0
-
Watch the
publish-pypijob in Actions. When it's green, the new version is live on PyPI and a GitHub Release exists for the tag.
The tag must start with v (e.g. v0.2.0) — that prefix is what gates the
publish job. Pushing to main without a tag only runs tests and builds the
wheel artifact; it never publishes.
License
Apache-2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dropmcp-0.2.0.tar.gz.
File metadata
- Download URL: dropmcp-0.2.0.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f853447349deef6bb25f3e5e91ffb48840454c8f1b4cbe3bb6acb9909710f7e2
|
|
| MD5 |
d9de3aa7e7cb3aaba93941c2a29dc35d
|
|
| BLAKE2b-256 |
63c5b6d961931eb417c47fbe5cd1fdcceb8bc2abba0e292835a96ba98c7f1142
|
Provenance
The following attestation bundles were made for dropmcp-0.2.0.tar.gz:
Publisher:
ci.yml on agoda-com/dropmcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dropmcp-0.2.0.tar.gz -
Subject digest:
f853447349deef6bb25f3e5e91ffb48840454c8f1b4cbe3bb6acb9909710f7e2 - Sigstore transparency entry: 1848283000
- Sigstore integration time:
-
Permalink:
agoda-com/dropmcp@b07ce983350e6946088a8f4ba16f9dec9f76b5a0 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/agoda-com
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@b07ce983350e6946088a8f4ba16f9dec9f76b5a0 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dropmcp-0.2.0-py3-none-any.whl.
File metadata
- Download URL: dropmcp-0.2.0-py3-none-any.whl
- Upload date:
- Size: 124.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
96684984463a8abf98b4be460078986d7c770a6b462f94ce4da2e6e88299f7c4
|
|
| MD5 |
a63509c552d2089bfaf29e46e0a9749f
|
|
| BLAKE2b-256 |
1d186410eef008a21a59a65de96b5a3444d08da27e58d74de044bab433dc116b
|
Provenance
The following attestation bundles were made for dropmcp-0.2.0-py3-none-any.whl:
Publisher:
ci.yml on agoda-com/dropmcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dropmcp-0.2.0-py3-none-any.whl -
Subject digest:
96684984463a8abf98b4be460078986d7c770a6b462f94ce4da2e6e88299f7c4 - Sigstore transparency entry: 1848283124
- Sigstore integration time:
-
Permalink:
agoda-com/dropmcp@b07ce983350e6946088a8f4ba16f9dec9f76b5a0 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/agoda-com
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
ci.yml@b07ce983350e6946088a8f4ba16f9dec9f76b5a0 -
Trigger Event:
push
-
Statement type: