feat(packaging)!: publish as trsdn-markitdown-mcp via PyPI Trusted Publishing - #48
Conversation
…blishing The PyPI name `markitdown-mcp` is owned by Microsoft's official project, so this independent server is published as `trsdn-markitdown-mcp`. - rename the distribution to `trsdn-markitdown-mcp` (import package `markitdown_mcp` and the `markitdown-mcp` command are unchanged) - add a `trsdn-markitdown-mcp` console-script alias and `__main__.py` so the server can be started via `uvx` or `python -m markitdown_mcp` - complete publish metadata (SPDX license, license-files, maintainers, classifiers, keywords, project URLs) - rewrite release.yml around a `build` + `publish` pair using OIDC Trusted Publishing (environment `pypi`, `id-token: write`, no API tokens) with `twine check` and a wheel smoke test before publishing - prune tests/docs/examples/scripts/schemas from the sdist - update README, docs and install script to the new distribution name and add a prominent "not Microsoft's official package" notice BREAKING CHANGE: the PyPI distribution name changes from `markitdown-mcp` to `trsdn-markitdown-mcp`. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
Reverts the over-aggressive rewrite of release.yml. The original job chain
(validate-release, quality-gates with the 3.10/3.11/3.12 matrix, security-scan,
build-package, generate-changelog, create-github-release, update-docs,
post-release-validation) and the concurrency group are restored unchanged.
Trusted Publishing is now additive:
- new `publish` job with needs: [validate-release, quality-gates, security-scan,
build-package, generate-changelog], `environment: pypi`,
`permissions: { id-token: write }` and pypa/gh-action-pypi-publish, no secrets
- `create-github-release` now needs `publish`, so the GitHub release is created
after the PyPI upload (and still runs for prereleases, where publish is skipped)
- workflow-level permissions reduced to `contents: read`; `id-token: write` only
in `publish`, `contents: write` only in `create-github-release`/`update-docs`
- `workflow_dispatch` with a required `tag` input; all checkouts resolve
`inputs.tag || github.ref` so a manual run builds the tagged commit
- version sync no longer uses a bare `sed s/version = ".*"/`, which also rewrote
`target-version = "py310"` and `python_version = "3.10"` in the [tool.*]
sections of pyproject.toml
- package verification now exercises markitdown-mcp, trsdn-markitdown-mcp and
`python -m markitdown_mcp` with a real tools/list request, and reads the
version via importlib.metadata; PyPI names updated to trsdn-markitdown-mcp
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Nachgebessert: Release-Pipeline wiederhergestellt (eb0091c)Berechtigter Einwand — das Zusammenstreichen der Vollständig erhalten
Neu / geändert
publish:
needs: [validate-release, quality-gates, security-scan, build-package, generate-changelog]
if: needs.validate-release.outputs.is-prerelease == 'false'
environment: pypi
permissions:
id-token: write
Reihenfolge — Permissions — workflow-weit auf Einzeln begründete Änderungen an bestehenden Schritten
Validierung
Danke für den Hinweis auf die angelegten Environments |
Both failures are pre-existing on main and unrelated to the packaging change;
they only surfaced now because CI installs an unpinned `ruff>=0.1.0` and a newer
release changed behaviour.
- ruff now also formats Python blocks embedded in Markdown, so AGENTS.md (not
touched by this PR) failed `ruff format --check`. Applied `ruff format`; the
diff is purely quote/wrapping style inside documentation snippets.
- pr-feedback.yml counted format issues with
`$(... | grep -c "would reformat" || echo "0")`. `grep -c` prints `0` *and*
exits 1 when nothing matches, so the substitution became the literal "0\n0",
which broke `$((total_issues + format_issues))` and the later `[ -gt ]`
comparison ("Invalid format '0'"). Newer ruff also reports
"N files would be reformatted", which the old pattern never matched. Now the
summary line is parsed with a safe fallback.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
🔍 PR Analysis ResultsPR: #48 | Commit: 🎨 Code Formatting✅ All files properly formatted 🔧 Code Linting✅ No linting issues found 📝 Type Checking❌ Type checking issues found Click to see type issuesFix: Add proper type annotations and resolve type errors 🔒 Security Analysis✅ No security issues detected 📊 Test Coverage Analysis✅ Coverage 81.71641791044776% meets 80% requirement 🧹 Dead Code Analysis✅ Dead code analysis completed 📋 Summary
🔧 Quick Fix Commands:# Fix formatting and auto-fixable linting issues
ruff format .
ruff check . --fix
# Run tests with coverage
pytest tests/unit/ --cov=markitdown_mcp --cov-report=term-missing
# Check security
bandit -r markitdown_mcp/This analysis was automatically generated by the PR feedback workflow. |
🔍 CI Quality Gates SummaryOverall Status: ✅ All Passed
🔗 Quick Links🛠️ Quick Fix Commands# Fix most issues automatically
ruff format .
ruff check . --fix
# Run tests locally
pytest tests/unit/ --cov=markitdown_mcp
# Check types
mypy markitdown_mcpLast updated: 2026-08-24 21:46:17 UTC |
🔍 PR Quality SummaryCI Status✅ Security: success Metrics
Quality Checks
MCP Tools
🤖 Auto-generated by CI • Last updated: 2026-08-24 21:49 UTC |
CI ist grün (56 pass / 0 fail)Nach dem Restore waren drei Checks rot — beide Ursachen sind vorbestehend auf
Verifikation: Falls gewünscht, kann |
Why
The PyPI name
markitdown-mcpis already taken by Microsoft's official MarkItDown project (v0.0.1a4). This repository is an independent project, so it will be published astrsdn-markitdown-mcp(verified available on PyPI) using Trusted Publishing (GitHub Actions OIDC) — no API tokens.PyPI publisher configuration (must match exactly)
trsdn-markitdown-mcptrsdn/markitdown-mcprelease.ymlpypiChanges
Packaging (
pyproject.toml)name→trsdn-markitdown-mcp. The import package staysmarkitdown_mcp;[tool.setuptools.packages.find]still resolves exactly one top-level package (verified viatop_level.txt).license = "MIT"+license-files,maintainers, extra classifiers, keywords,requires-python, richer[project.urls]. Removed the deprecated[project.license] texttable and the redundant license classifier (setuptools>=77).[project.scripts]:markitdown-mcpkept, plus atrsdn-markitdown-mcpalias souvx trsdn-markitdown-mcpworks directly.markitdown_mcp/__main__.py→python -m markitdown_mcpworks.No import shadowing — the top-level module is
markitdown_mcp, clearly distinct from the upstreammarkitdowndependency.top_level.txtcontains onlymarkitdown_mcp.Release workflow (
.github/workflows/release.yml) — additive, +92/−22The existing job chain is fully preserved:
validate-release,quality-gates(matrix 3.10/3.11/3.12 + MCP protocol validation),security-scan(Bandit + dependency audit),build-package,generate-changelog,create-github-release,update-docs,post-release-validation, and theconcurrencygroup.Added on top:
publishjob:needs: [validate-release, quality-gates, security-scan, build-package, generate-changelog],environment: pypi,permissions: { id-token: write },pypa/gh-action-pypi-publish@release/v1. No secrets. Replaces the oldpublish-pypijob that pointed atenvironment: release.create-github-releasenow needspublish, so the GitHub release is created after the PyPI upload. Its condition was tightened so prereleases (wherepublishis skipped) still get a release, but a failed publish does not.contents: read;id-token: writeonly inpublish;contents: writeonly increate-github-release/update-docs; unusedpackages: writeremoved.workflow_dispatchwith a requiredtaginput; checkouts resolveref: ${{ inputs.tag || github.ref }}.Fixes to existing steps (each justified in this comment):
sed s/version = ".*"/, which also rewrotetarget-version = "py310"andpython_version = "3.10"in the[tool.*]sections — i.e. every release shipped a corrupted ruff/mypy config. Replaced with an anchored, single-occurrencere.subnthat fails loudly.echo '{}' | markitdown-mcp || echo "…skipped"could never fail ({}has nomethod, and||swallowed errors). Replaced with a realtools/listrequest asserting ≥3 tools, run against all three entrypoints.markitdown_mcp.__version__(1.0.0, drifted from the built version) → nowimportlib.metadata.version("trsdn-markitdown-mcp").if-no-files-found: erroron the artifact upload.Distribution hygiene (
MANIFEST.in)Prunes
tests/,docs/,examples/,scripts/,schemas/,.github/,.env*; removed the include of the non-existentmcp_config.json.Docs
README gets a PyPI badge, a prominent "this is NOT Microsoft's official
markitdown-mcp" callout, PyPI/uvx install instructions and anuvxMCP client config example; hardcoded local paths and the reference to the non-existentrun_server.pywere removed.RELEASE.mddocuments the Trusted Publishing setup and the full job chain.docs/index.rst,docs/guides/KNOWN_ISSUES.md,scripts/install-all-deps.shandpre-release.ymlnow use the new distribution name.Validation
sdist contents (no tests, no
.env, no sample documents; 28 KB):Entrypoints verified against the installed wheel in a clean venv —
markitdown-mcp,trsdn-markitdown-mcpandpython -m markitdown_mcpeach return the 3 MCP tools (convert_file,list_supported_formats,convert_directory).No upload to PyPI was performed.
Follow-ups (not in this PR)
v*tag. (The GitHub environmentspypiandtest-pypialready exist.)pre-release.ymlpublishes to TestPyPI withenvironment: test-pypivia OIDC — that needs its own pending publisher on TestPyPI (workflow filepre-release.yml) if pre-releases are to be used.trsdn/markitdown-mcp-serverlooks like an abandoned duplicate of this project (same description, nopyproject.toml). Nothing was changed there; consider archiving it to avoid confusion.