Author: Uttam Jaiswal Date: February 2026 Project: DevOps Practices MCP Server Repository: https://github.com/ai-4-devops/devops-practices Package: https://pypi.org/project/devops-practices-mcp/
- Introduction
- Phase 1: Repository Setup and Configuration
- Phase 2: CI/CD Migration
- Phase 3: MCP Registry Submission - The Dual Approach
- Phase 4: The PyPI Pivot
- Phase 5: Final Registry Publication
- Lessons Learned
- Complete Timeline
This is the story of publishing my first MCP (Model Context Protocol) server to Anthropic's official registry. What started as a simple submission turned into a comprehensive journey through Python packaging, CI/CD setup, and navigating the MCP registry validation system.
The Goal: Publish a DevOps knowledge base MCP server that provides best practices and templates for infrastructure teams.
The Challenge: Understanding the MCP registry requirements, dealing with validation errors, and choosing the right publishing approach when the initial path hit blockers.
The Outcome: Successfully published to both PyPI and the MCP Registry with professional CI/CD infrastructure and comprehensive documentation.
# Configure remote
cd /home/ukj/.mcp-servers/devops-practices
git remote remove origin
git remote add origin git@github.com:ai-4-devops/devops-practices.git
# Push everything
git push -u origin main
git push origin develop
git push origin --tagsError: Host key verification failed
Solution: Manual SSH approval in terminal before git commands work. This is a one-time security verification.
Configured comprehensive GitHub settings:
Features Enabled:
- ✅ Issues (for bug tracking)
- ✅ Projects (for roadmap)
- ✅ Discussions (for community)
- ✅ Wiki (for extended docs)
Branch Protection (main):
- Require pull request before merging
- Require status checks to pass
- Require at least 1 approval
- Block force pushes
- Do not allow deletions
Branch Protection (develop):
- Require pull request before merging
- Require status checks to pass
- Block force pushes
Status Badges Added:
[](https://github.com/ai-4-devops/devops-practices/actions/workflows/ci.yml)
[](https://opensource.org/licenses/MIT)
[](https://www.python.org/downloads/)
[](https://modelcontextprotocol.io)Repository had .gitlab-ci.yml but was now on GitHub. Needed to migrate 7 validation jobs to GitHub Actions while preserving all logic.
Original GitLab CI Jobs:
- health-check
- python-validation
- practice-validation
- template-validation
- link-checker
- release-validation
- branch-info
GitHub Actions Conversion:
Created .github/workflows/ci.yml:
name: CI/CD Pipeline
on:
push:
branches:
- main
- develop
- 'feature/**'
- 'release/**'
- 'hotfix/**'
pull_request:
branches:
- main
- develop
jobs:
health-check:
name: Health Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- run: bash health-check.sh
- uses: actions/upload-artifact@v4
if: failure()
with:
name: health-check-logs
path: health-check.log
retention-days: 7
python-validation:
name: Python Validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.10'
- run: pip install -r requirements.txt
- run: |
python -c "import json; import logging; import sys; from pathlib import Path"
python -m py_compile mcp-server.py
# ... additional jobs for practice, template, link validationKey Differences:
- GitLab:
image: python:3.10→ GitHub:uses: actions/setup-python@v5 - GitLab:
script:→ GitHub:run: - GitLab:
artifacts:→ GitHub:uses: actions/upload-artifact@v4
Cleanup:
git rm .gitlab-ci.yml
git commit -m "ci: Remove GitLab CI configuration (migrated to GitHub Actions)"Anthropic's MCP Registry offers two submission methods:
- Discussion-based: Manual review by maintainers
- CLI-based: Automated validation and publishing
I decided to do BOTH for maximum coverage and redundancy.
Created comprehensive post: modelcontextprotocol/registry#974
Submission Structure:
## Server Name
io.github.ai-4-devops/devops-practices
## Description
AI-powered DevOps knowledge base providing 11 best practices and 7 templates...
## Repository
https://github.com/ai-4-devops/devops-practices
## Installation
npx -y @anthropic-ai/mcp-server-devops-practices
## Relevant Links
- Documentation: [README.md]
- Practices: List of 11 practices
- Templates: List of 7 templatesStatus: Submitted, awaiting manual review
Installation:
# Install Go and build CLI
sudo apt-get update && sudo apt-get install -y golang-go
cd /tmp
git clone https://github.com/modelcontextprotocol/registry.git
cd registry/cli/mcp-publisher
go build -o ~/registry/bin/mcp-publisherAuthentication:
~/registry/bin/mcp-publisher login github
# Opens browser → GitHub OAuth → Device code: 0302-083DThis is where the real learning happened. The server.json file went through 6+ iterations before passing validation.
{
"name": "devops-practices",
"description": "...",
"version": "1.3.0"
}Error: expected length >= 1 at body.$schema
Fix: Added schema version:
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
...
}{
"description": "AI-powered DevOps knowledge base for Claude - MCP server with 11 best practices, 7 templates, and automation tools for infrastructure teams"
}Error: expected length <= 100 at body.description
Length: 147 characters
Fix: Shortened to 81 characters:
{
"description": "AI-powered DevOps knowledge base with practices, templates, and automation tools"
}{
"name": "devops-practices"
}Error: expected string to match pattern ^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$
Fix: Added namespace:
{
"name": "io.github.ai-4-devops/devops-practices"
}{
"repository": "https://github.com/ai-4-devops/devops-practices"
}Error: expected object, received string
Fix: Proper repository object:
{
"repository": {
"url": "https://github.com/ai-4-devops/devops-practices",
"source": "github"
}
}{
"packages": [{
"packageArguments": [
{"name": "-m", "value": "devops_practices_mcp"}
]
}]
}Error: value must be 'positional' at body.packages[0].packageArguments[0].type
Fix: Added type field:
{
"packageArguments": [
{"type": "named", "name": "-m", "value": "devops_practices_mcp"}
]
}Attempted Configuration:
{
"packages": [{
"registryType": "github",
"identifier": "ai-4-devops/devops-practices"
}]
}Error: unsupported registry type: github
Supported Types: npm, pypi, nuget, maven
Impact: CLI-based publishing blocked! This led to Phase 6...
Error:
You do not have permission to publish this server.
You have permission to publish: io.github.ukjaiswal/*
Attempting to publish: io.github.ai-4-devops/devops-practices
you may need to make your organization membership public
Fix:
- Navigate to https://github.com/orgs/ai-4-devops/people
- Change membership from Private → Public
Error: Invalid or expired Registry JWT token
Fix: Re-authenticate:
~/registry/bin/mcp-publisher login githubLesson: Tokens expire after some time; keep authentication fresh during multi-step processes.
With GitHub registry type unsupported, I had to publish to a supported registry. PyPI (Python Package Index) was the natural choice for a Python-based MCP server.
devops-practices/
├── mcp-server.py
├── practices/
└── templates/
devops-practices/
├── src/
│ └── devops_practices_mcp/
│ ├── __init__.py
│ ├── __main__.py
│ └── practices/
│ └── templates/
├── pyproject.toml
└── README.md
Why uv? Modern, fast Python package manager recommended for 2026.
# Install uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create package structure
mkdir -p src/devops_practices_mcp/{practices,templates}
cp mcp-server.py src/devops_practices_mcp/__main__.py
cp -r practices/* src/devops_practices_mcp/practices/
cp -r templates/* src/devops_practices_mcp/templates/
# Create __init__.py
cat > src/devops_practices_mcp/__init__.py << 'EOF'
"""DevOps Practices MCP Server.
Provides shared DevOps practices and templates for infrastructure projects.
"""
__version__ = "1.3.0"
def main():
"""Entry point for the MCP server."""
from . import __main__
__main__.main()
__all__ = ["main", "__version__"]
EOF[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "devops-practices-mcp"
version = "1.3.0"
description = "AI-powered DevOps knowledge base with practices, templates, and automation tools"
readme = "README.md"
requires-python = ">=3.10"
license = {text = "MIT"}
authors = [
{name = "Uttam Jaiswal", email = "uttam.jaiswal@example.com"}
]
keywords = [
"mcp", "devops", "automation", "best-practices",
"infrastructure", "configuration-management",
"templates", "knowledge-base", "claude", "ai"
]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Intended Audience :: System Administrators",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: System :: Systems Administration",
]
[project.urls]
Homepage = "https://github.com/ai-4-devops/devops-practices"
Documentation = "https://github.com/ai-4-devops/devops-practices/blob/main/README.md"
Repository = "https://github.com/ai-4-devops/devops-practices"
Issues = "https://github.com/ai-4-devops/devops-practices/issues"
[project.scripts]
devops-practices-mcp = "devops_practices_mcp:main"
[tool.hatch.build.targets.wheel]
packages = ["src/devops_practices_mcp"]
[tool.hatch.build]
include = [
"src/devops_practices_mcp/**/*.py",
"src/devops_practices_mcp/practices/**/*.md",
"src/devops_practices_mcp/templates/**/*.md",
]Steps:
- Created account at https://pypi.org/account/register/
- Verified email address
- Generated API token at https://pypi.org/manage/account/token/
- Token Scope Question: Should scope be "Entire account" or project-specific?
Answer: For first upload, use "Entire account" scope. After package exists, can create project-scoped tokens for better security.
# Build package
cd /home/ukj/.mcp-servers/devops-practices
uv build
# Output:
# Building devops-practices-mcp
# ├── Built devops_practices_mcp-1.3.0-py3-none-any.whl
# └── Built devops_practices_mcp-1.3.0.tar.gz
# Publish to PyPI
uv publish
# Enter PyPI token when prompted
# [token hidden for security]
# Success!
# Uploading devops_practices_mcp-1.3.0.tar.gz
# Uploading devops_practices_mcp-1.3.0-py3-none-any.whlPackage live at: https://pypi.org/project/devops-practices-mcp/
Installation test:
pip install devops-practices-mcp
devops-practices-mcp --version
# Output: 1.3.0{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.ai-4-devops/devops-practices",
"description": "AI-powered DevOps knowledge base with practices, templates, and automation tools",
"repository": {
"url": "https://github.com/ai-4-devops/devops-practices",
"source": "github"
},
"version": "1.3.0",
"packages": [
{
"registryType": "pypi",
"identifier": "devops-practices-mcp",
"version": "1.3.0",
"transport": {"type": "stdio"},
"runtimeHint": "python3",
"packageArguments": [
{"type": "named", "name": "-m", "value": "devops_practices_mcp"}
],
"environmentVariables": []
}
]
}First Attempt:
~/registry/bin/mcp-publisher publish server.jsonError:
PyPI package 'devops-practices-mcp' ownership validation failed.
The server name 'io.github.ai-4-devops/devops-practices' must appear as
'mcp-name: io.github.ai-4-devops/devops-practices' in the package README.
Added to README.md:
# DevOps Practices MCP Server
mcp-name: io.github.ai-4-devops/devops-practices
AI-powered DevOps knowledge base providing best practices and templates...Why? This marker proves PyPI package ownership for MCP registry. It links the PyPI package to the MCP server name.
Since we modified README, needed new version:
# Update version in all files
# - pyproject.toml
# - src/devops_practices_mcp/__init__.py
# - server.json
# Rebuild and republish to PyPI
uv build
uv publishUpload output:
Uploading devops_practices_mcp-1.3.1-py3-none-any.whl (70 KB)
Uploading devops_practices_mcp-1.3.1.tar.gz (60 KB)
~/registry/bin/mcp-publisher publish server.jsonOutput:
Publishing server io.github.ai-4-devops/devops-practices to version 1.3.1
Resolving package identifier: devops-practices-mcp
Downloading package from pypi
Extracting package
Validating package
Searching for 'mcp-name: io.github.ai-4-devops/devops-practices' in README
✓ Successfully published
✓ Server io.github.ai-4-devops/devops-practices version 1.3.1
git add -A
git commit -m "$(cat <<'EOF'
feat: Successfully publish to MCP Registry v1.3.1
- Added mcp-name marker to README for ownership validation
- Bumped version from 1.3.0 to 1.3.1
- Rebuilt and republished to PyPI
- Successfully published to MCP Registry
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
EOF
)"
git push origin mainAfter v1.3.1 was successfully published, we discovered and fixed critical issues while also implementing a major reorganization.
Critical Bug Fix:
- Fixed MCP server stdio protocol corruption
- Root cause: Default logging wrote to stderr, corrupting JSON-RPC 2.0 messages
- Solution: FileHandler-only logging to
~/.cache/claude/mcp-devops-practices.log - Impact: Server stability now matches dev-kit reliability
Major Feature: GG-SS Reorganization
- Reorganized all 11 practices with Group-Sequence prefix pattern
- Created 4 logical groups for better discoverability:
- Group 01: Workflow & Processes (3 practices)
- Group 02: Version Control & PM (2 practices)
- Group 03: Infrastructure & Configuration (3 practices)
- Group 04: Documentation Standards (3 practices)
- Used
git mvto preserve 100% git history - Inspired by dev-kit's hierarchical organization
New Features:
- Added 2 new MCP tools:
get_practice_summary,search_practices - Enhanced
list_practiceswith metadata extraction - Improved server from 237 → 337 lines
- Total MCP tools: 5 → 7
cd /home/ukj/.mcp-servers/devops-practices-mcp
# Clean previous builds
rm -rf dist/ build/ *.egg-info
# Build with uv (modern Python package manager)
uv build
# Output:
# Successfully built devops_practices_mcp-1.4.0-py3-none-any.whl (80 KB)
# Successfully built devops_practices_mcp-1.4.0.tar.gz (64 KB)# Using uv publish
uv publish
# Note: .pypirc configuration recommended for credentials
# ~/.pypirc with [pypi] section containing username and passwordResult: ✅ https://pypi.org/project/devops-practices-mcp/1.4.0/
Challenge Discovered: The registry structure had changed since v1.3.1!
Old path (from Phase 5):
cd /tmp/registry/cli/mcp-publisher # ❌ No longer existsNew path (February 2026):
cd /tmp/registry/cmd/publisher # ✅ Correct pathUpdated Build Process:
# Clone registry (if not already done)
cd /tmp
git clone https://github.com/modelcontextprotocol/registry.git
# Navigate to CORRECT path
cd /tmp/registry/cmd/publisher
# Build mcp-publisher
mkdir -p ~/registry/bin
go build -o ~/registry/bin/mcp-publisher
# Make executable
chmod +x ~/registry/bin/mcp-publisherAuthentication:
~/registry/bin/mcp-publisher login github
# Opens browser for GitHub OAuth
# Authorize and return to terminalPublish to Registry:
cd /home/ukj/.mcp-servers/devops-practices-mcp
~/registry/bin/mcp-publisher publish server.jsonExpected Output:
Publishing server io.github.ai-4-devops/devops-practices to version 1.4.0
Resolving package identifier: devops-practices-mcp
Downloading package from pypi
Extracting package
Validating package
Searching for 'mcp-name: io.github.ai-4-devops/devops-practices' in README
✓ Successfully published
✓ Server io.github.ai-4-devops/devops-practices version 1.4.0
1. Registry Structure Evolution
- MCP registry moved from
cli/mcp-publisher→cmd/publisher - Always check current repository structure
- Don't blindly follow old documentation
2. Token Storage Security
- Use
~/.pypircfor PyPI credentials (industry standard) - Keep tokens outside repository
- Use chmod 600 for proper permissions
3. Breaking Changes Communication
- v1.4.0 had breaking changes (practice name changes)
- Comprehensive CHANGELOG.md is critical
- Provide migration guide with examples
4. Git History Preservation
git mvpreserves 100% rename history- Shows as "renamed" not "deleted + added"
- Critical for code archaeology and blame
5. Version Bumping
- Update ALL version references consistently:
- pyproject.toml
- src/package/init.py
- server.json (both places)
- Update CHANGELOG.md
Preparation Phase:
- Fixed critical logging bug
- Implemented GG-SS reorganization (11 practices renamed)
- Enhanced MCP server with 2 new tools
- Updated all documentation
- Committed 12 commits on feature branch
- Merged PR to main (no squash - preserved history)
- Tagged v1.4.0 in git
Publication Phase:
- Built package with
uv build(5 seconds) - Published to PyPI with
uv publish(30 seconds) - Discovered registry structure changed
- Found correct path:
cmd/publisher - Built mcp-publisher CLI
- Authenticated with GitHub OAuth
- Published to MCP Registry (1 minute)
Total Time: ~2 minutes (after initial troubleshooting)
| Aspect | v1.3.1 | v1.4.0 | Change |
|---|---|---|---|
| Practices | 11 | 11 | Reorganized with GG-SS |
| Templates | 7 | 7 | No change |
| MCP Tools | 5 | 7 | +2 new tools |
| Code Lines | 237 | 337 | +100 lines |
| Stability | Unstable | Stable | Critical fix |
| Organization | Flat | Hierarchical | 4 groups |
- GitHub Actions syntax differs significantly from GitLab CI
- Core logic (validation scripts) remains the same
- Pay attention to artifact upload/download differences
- Test workflows thoroughly before relying on them
- Dual approach (Discussion + CLI) provides redundancy
server.jsonschema is strict - expect multiple validation failures- Read error messages carefully - they're specific and helpful
- Not all registry types are supported (github is NOT supported)
- Proper Python package structure is essential (src layout recommended)
pyproject.tomlwith complete metadata improves discoverability- Use modern tools like
uvfor faster, simpler workflows - Account-scoped tokens for first upload, project-scoped for maintenance
- MCP registry validates PyPI package ownership
mcp-name: namespace/server-namemarker in README is required- Version bumps are needed when README changes
- The marker links PyPI package to MCP server identity
- OAuth tokens expire - keep authentication fresh
- Organization membership must be public for publishing
- Permission errors often indicate configuration issues, not bugs
- Re-authenticate when in doubt
- Semantic versioning (X.Y.Z) is expected
- Bump patch version (Z) for documentation changes
- Keep versions consistent across all files
- Tag releases in git for traceability
- Comprehensive README helps users and reviewers
- Status badges communicate project health
- Clear installation instructions are critical
- Link to practices and templates for transparency
- Publishing involves multiple subsystems (Git, GitHub, PyPI, MCP Registry)
- Each system has its own validation rules and timing
- Errors are learning opportunities
- The journey from private to public is complex but rewarding
- ✅ Set up GitHub repository under ai-4-devops organization
- ✅ Configured repository settings and branch protection
- ✅ Enabled Issues, Projects, Discussions, and Wiki
- ✅ Added professional status badges to README
- ✅ Converted GitLab CI to GitHub Actions
- ✅ Added professional status badges
- ✅ Posted Discussion-based submission (#974)
- ✅ Installed mcp-publisher CLI
- ✅ Attempted CLI-based submission
- ❌ Hit unsupported registry type blocker
- ✅ Created proper Python package structure
- ✅ Built package with uv
- ✅ Created PyPI account and API token
- ✅ Published v1.3.0 to PyPI
- ✅ Updated server.json to use PyPI
- ❌ Hit ownership validation error
- ✅ Added mcp-name marker to README
- ✅ Bumped version to 1.3.1
- ✅ Republished to PyPI
- ✅ Successfully published to MCP Registry
- ✅ Verified installation from both PyPI and MCP Registry
- ✅ Created this documentation
- ✅ Fixed critical MCP server stability issue (stdio logging)
- ✅ Implemented GG-SS reorganization (11 practices, 4 groups)
- ✅ Added 2 new MCP tools (get_practice_summary, search_practices)
- ✅ Enhanced list_practices with metadata
- ✅ Updated comprehensive CHANGELOG.md
- ✅ Merged PR #2 to main (12 commits, preserved history)
- ✅ Tagged v1.4.0 in git
- ✅ Built and published to PyPI
- ✅ Discovered registry path changed (cli → cmd)
- ✅ Published to MCP Registry with correct path
- ✅ Updated JOURNEY.md with v1.4.0 experience
- GitHub Repository: https://github.com/ai-4-devops/devops-practices
- PyPI Package: https://pypi.org/project/devops-practices-mcp/
- MCP Registry Discussion: modelcontextprotocol/registry#974
- Personal Website: https://uk4.in
- LinkedIn: Connect with me
- uv: Python package management
- mcp-publisher: MCP registry CLI
- GitHub Actions: CI/CD automation
- hatchling: Python build backend
server.json: MCP registry configurationpyproject.toml: Python package metadata.github/workflows/ci.yml: CI/CD pipelineREADME.md: Project documentation with mcp-name marker
Publishing an MCP server to the official registry is more than just running a publish command. It's a journey through packaging standards, registry validation, CI/CD setup, and navigating multiple publishing systems.
The failures encountered along the way - from server.json validation errors to PyPI ownership validation - were not obstacles but learning opportunities. Each error message provided specific guidance on what needed to be fixed.
For anyone attempting a similar journey:
- Set up proper infrastructure - GitHub Actions, branch protection, and badges matter
- Structure properly - proper Python packaging pays dividends
- Document thoroughly - help others learn from your experience
- Read error messages carefully - they're specific and guide you to solutions
- Be persistent - multi-system publishing takes time and patience
The DevOps Practices MCP Server is now live and available for the Claude AI community to use. It provides 11 best practices and 7 templates for infrastructure teams, all validated and published through proper channels.
Final Status (v1.4.0):
- ✅ GitHub: https://github.com/ai-4-devops/devops-practices
- ✅ PyPI: https://pypi.org/project/devops-practices-mcp/ (v1.4.0)
- ✅ MCP Registry: io.github.ai-4-devops/devops-practices v1.4.0
- ✅ Git Tags: v1.0.0, v1.2.0, v1.3.0, v1.4.0
- ✅ CI/CD: GitHub Actions with 7 validation jobs
- ✅ Documentation: Comprehensive README, CHANGELOG, and journey documentation
- ✅ Features: 11 practices (GG-SS organized), 7 templates, 7 MCP tools
- ✅ Stability: Critical logging fix - server now stable
Thank you for following this journey. I hope it helps you publish your own MCP servers successfully!
About the Author
Uttam Jaiswal is a DevOps engineer passionate about AI-powered development tools and infrastructure automation. This MCP server represents the intersection of DevOps best practices and AI-assisted development.
Connect: https://uk4.in | https://github.com/ukjaiswal | https://linkedin.com/in/uttamjaiswal