Add API documentation with GitHub Pages deployment
This adds automated deployment of a versioned API documentation landing
page using GitHub Pages. The landing page links to documentation hosted
on RubyDoc.info, the de facto standard documentation site for the Ruby
ecosystem. The landing page will update to reflect new releases.
Changes
-------
1. **Documentation generation script** (see `bin/generate-gh-pages.sh`)
Copies and commits documentation files to the gh-pages branch. The
script uses git worktrees to isolate the process from the main
workspace.
The script:
- Creates the gh-pages branch as an orphan branch if it doesn't exist
- Parses semantic versions from tag names, ignoring arbitrary
prefixes (e.g., tags `1.2.3`, `v1.2.3`, and `release-1.2.3` all
create `v1.2.3`)
- Determines the latest version using semantic version sorting
- Copies static Jekyll template files from `docs/` to the gh-pages
root (for the latest version only)
- Generates `docs/_data/versions.yml` with a list of all versions
for the Jekyll templates to consume
2. **Jekyll template files** (see `docs/` directory)
- `docs/_config.yml` - Jekyll configuration
- `docs/index.md` - Landing page template that links to all versions
on RubyDoc.info based on generated `docs/_data/versions.yml`
- `docs/latest/index.html` - Redirect page template that redirects
to the latest documentation on RubyDoc.info
3. **GitHub Actions workflow** (see `.github/workflows/release.yml`)
Added a `publish_gh_pages` job that runs after the `publish_gem` job
on release events. The job invokes the generation script with the
release tag name, then pushes the updated gh-pages branch to deploy
the documentation.
4. **CI validation** (see `.github/workflows/ci.yml`)
Added a `yard` job that runs YARD validation with `--no-output`.
This ensures YARD can successfully parse the codebase (without
generating output), catching documentation issues early in CI.
5. **YARD dependencies** (see `Gemfile`)
Added `yard` and `yard-sorbet` gems as development dependencies to
support documentation validation in CI.
YARD documentation is automatically generated and hosted by
RubyDoc.info when the gem is published to RubyGems.org.
6. **Documentation links** (see `README.md` and `mcp.gemspec`)
Added links to the published API documentation on RubyDoc.info in
the README and gemspec metadata.
Documentation URL
-----------------
Custom documentation will be available at:
https://modelcontextprotocol.github.io/ruby-sdk/
RubyDoc.info documentation will be accessible at:
- https://rubydoc.info/gems/mcp (latest version)
- https://rubydoc.info/gems/mcp/1.2.3 (specific versions)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
400a56e83d
commit
281c334075
9 changed files with 202 additions and 0 deletions
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
|
|
@ -31,3 +31,14 @@ jobs:
|
|||
ruby-version: 3.2 # Specify the oldest supported Ruby version.
|
||||
bundler-cache: true
|
||||
- run: bundle exec rake rubocop
|
||||
|
||||
yard:
|
||||
runs-on: ubuntu-latest
|
||||
name: YARD Documentation
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: 3.2 # Specify the oldest supported Ruby version.
|
||||
bundler-cache: true
|
||||
- run: bundle exec yard --no-output
|
||||
|
|
|
|||
32
.github/workflows/release.yml
vendored
32
.github/workflows/release.yml
vendored
|
|
@ -23,3 +23,35 @@ jobs:
|
|||
bundler-cache: true
|
||||
ruby-version: 3.4
|
||||
- uses: rubygems/release-gem@v1
|
||||
|
||||
publish_gh_pages:
|
||||
if: github.repository_owner == 'modelcontextprotocol'
|
||||
name: Publish Documentation to GitHub Pages
|
||||
runs-on: ubuntu-latest
|
||||
needs: [publish_gem]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for all branches and tags
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Get version tag
|
||||
id: version
|
||||
run: |
|
||||
git fetch --tags
|
||||
TAG=$(git describe --tags --exact-match HEAD)
|
||||
echo "tag=${TAG}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate GitHub Pages
|
||||
run: ./bin/generate-gh-pages.sh ${{ steps.version.outputs.tag }}
|
||||
|
||||
- name: Push to gh-pages
|
||||
run: git push origin gh-pages
|
||||
|
|
|
|||
2
Gemfile
2
Gemfile
|
|
@ -17,6 +17,8 @@ gem "activesupport"
|
|||
gem "debug"
|
||||
gem "rake", "~> 13.0"
|
||||
gem "sorbet-static-and-runtime"
|
||||
gem "yard", "~> 0.9"
|
||||
gem "yard-sorbet", "~> 0.9"
|
||||
|
||||
group :test do
|
||||
gem "faraday", ">= 2.0"
|
||||
|
|
|
|||
|
|
@ -932,3 +932,8 @@ The client provides a wrapper class for tools returned by the server:
|
|||
- `MCP::Client::Tool` - Represents a single tool with its metadata
|
||||
|
||||
This class provides easy access to tool properties like name, description, input schema, and output schema.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [SDK API documentation](https://rubydoc.info/gems/mcp)
|
||||
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
|
||||
|
|
|
|||
119
bin/generate-gh-pages.sh
Executable file
119
bin/generate-gh-pages.sh
Executable file
|
|
@ -0,0 +1,119 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Generates versioned documentation links and commits to gh-pages branch
|
||||
#
|
||||
# PURPOSE:
|
||||
# This script generates a landing page with links to API documentation on
|
||||
# RubyDoc.info for a specific version tag. This script is invoked by the
|
||||
# publish-gh-pages job in the GitHub Actions workflow
|
||||
# (.github/workflows/release.yml) when a release is published.
|
||||
#
|
||||
# HOW IT WORKS:
|
||||
# - Creates isolated git worktrees for the specified tag and gh-pages branch
|
||||
# - Copies static Jekyll template files from docs/
|
||||
# - Generates _data/versions.yml with list of versions
|
||||
# - Commits changes to gh-pages (does not push automatically)
|
||||
#
|
||||
# WORKFLOW:
|
||||
# 1. Run this script with a tag name: `generate-gh-pages.sh v1.2.3`
|
||||
# 2. Script generates docs and commits to local gh-pages branch
|
||||
# 3. Push gh-pages branch to deploy: `git push origin gh-pages`
|
||||
|
||||
# Parse semantic version from tag name (ignoring arbitrary prefixes)
|
||||
if [[ "${1}" =~ ([0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?)$ ]]; then
|
||||
VERSION="v${BASH_REMATCH[1]}"
|
||||
else
|
||||
echo "Error: Must specify a tag name that contains a valid semantic version"
|
||||
echo "Usage: ${0} <tag-name>"
|
||||
echo "Examples:"
|
||||
echo " ${0} 1.2.3"
|
||||
echo " ${0} v2.0.0-rc.1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TAG_NAME="${1}"
|
||||
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
||||
|
||||
echo "Generating documentation for tag: ${TAG_NAME}"
|
||||
|
||||
# Create temporary directories for both worktrees
|
||||
WORKTREE_DIR=$(mktemp -d)
|
||||
GHPAGES_WORKTREE_DIR=$(mktemp -d)
|
||||
|
||||
# Set up trap to clean up both worktrees on exit
|
||||
trap 'git worktree remove --force "${WORKTREE_DIR}" 2>/dev/null || true; \
|
||||
git worktree remove --force "${GHPAGES_WORKTREE_DIR}" 2>/dev/null || true' EXIT
|
||||
|
||||
echo "Creating worktree for ${TAG_NAME}..."
|
||||
git worktree add --quiet "${WORKTREE_DIR}" "${TAG_NAME}"
|
||||
|
||||
# Check if gh-pages branch exists
|
||||
if git show-ref --verify --quiet refs/heads/gh-pages; then
|
||||
echo "Creating worktree for existing gh-pages branch..."
|
||||
git worktree add --quiet "${GHPAGES_WORKTREE_DIR}" gh-pages
|
||||
elif git ls-remote --exit-code --heads origin gh-pages > /dev/null 2>&1; then
|
||||
echo "Creating worktree for gh-pages branch from remote..."
|
||||
git worktree add --quiet "${GHPAGES_WORKTREE_DIR}" -b gh-pages origin/gh-pages
|
||||
else
|
||||
echo "Creating worktree for new orphan gh-pages branch..."
|
||||
git worktree add --quiet --detach "${GHPAGES_WORKTREE_DIR}"
|
||||
git -C "${GHPAGES_WORKTREE_DIR}" checkout --orphan gh-pages
|
||||
git -C "${GHPAGES_WORKTREE_DIR}" rm -rf . > /dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
# Change to gh-pages worktree
|
||||
cd "${GHPAGES_WORKTREE_DIR}"
|
||||
|
||||
# Determine if this tag is the latest version
|
||||
echo "Determining if ${VERSION} is the latest version..."
|
||||
|
||||
# Get all existing version tags from the repository (reverse sorted, newest first)
|
||||
ALL_VERSIONS=$(
|
||||
git -C "${REPO_ROOT}" tag --list | \
|
||||
sed -nE 's/^[^0-9]*([0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?)$/v\1/p' | \
|
||||
sort -Vr
|
||||
)
|
||||
|
||||
# Get the latest version from all version tags
|
||||
LATEST_VERSION=$(echo "${ALL_VERSIONS}" | head -n 1)
|
||||
|
||||
if [ "${VERSION}" = "${LATEST_VERSION}" ]; then
|
||||
echo "${VERSION} is the latest version"
|
||||
else
|
||||
echo "${VERSION} is not the latest version (latest is ${LATEST_VERSION})"
|
||||
fi
|
||||
|
||||
# Update custom documentation for latest version
|
||||
if [ "${VERSION}" = "${LATEST_VERSION}" ]; then
|
||||
echo "Updating custom documentation..."
|
||||
|
||||
# Clean up old custom docs from gh-pages root
|
||||
echo "Cleaning gh-pages root..."
|
||||
git ls-tree --name-only HEAD | xargs -r git rm -rf
|
||||
|
||||
# Copy custom docs from docs/ directory
|
||||
echo "Copying custom docs from ${WORKTREE_DIR}/docs/..."
|
||||
cp -r "${WORKTREE_DIR}/docs/." "${GHPAGES_WORKTREE_DIR}/"
|
||||
fi
|
||||
|
||||
# Generate version data for Jekyll
|
||||
echo "Generating _data/versions.yml..."
|
||||
mkdir -p _data
|
||||
echo "${ALL_VERSIONS}" | sed 's/^v/- /' > _data/versions.yml
|
||||
|
||||
# Stage all changes
|
||||
git add .
|
||||
|
||||
# Commit if there are changes
|
||||
if git diff --staged --quiet; then
|
||||
echo "No changes to commit"
|
||||
else
|
||||
echo "Committing documentation for ${VERSION}..."
|
||||
git commit -m "Add ${VERSION} docs"
|
||||
|
||||
echo "Documentation committed to gh-pages branch!"
|
||||
echo "Push to remote to deploy to GitHub Pages"
|
||||
fi
|
||||
|
||||
echo "Done!"
|
||||
6
docs/_config.yml
Normal file
6
docs/_config.yml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# Use package name as site title
|
||||
title: "MCP Ruby SDK"
|
||||
|
||||
# Include generated files and directories which may start with underscores
|
||||
include:
|
||||
- "_*"
|
||||
7
docs/index.md
Normal file
7
docs/index.md
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
# Empty Jekyll front matter to enable Liquid templating (see {{ ... }} below)
|
||||
---
|
||||
|
||||
{% for version in site.data.versions -%}
|
||||
- [v{{ version }}](https://rubydoc.info/gems/mcp/{{ version }})
|
||||
{% endfor %}
|
||||
19
docs/latest/index.html
Normal file
19
docs/latest/index.html
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
# Empty Jekyll front matter to enable Liquid templating (see {{ ... }} below)
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Redirecting to latest documentation...</title>
|
||||
<meta http-equiv="refresh" content="0; url=https://rubydoc.info/gems/mcp">
|
||||
<link rel="canonical" href="https://rubydoc.info/gems/mcp">
|
||||
</head>
|
||||
<body>
|
||||
<p>Redirecting to <a href="https://rubydoc.info/gems/mcp">latest documentation</a>...</p>
|
||||
<script>
|
||||
window.location.href = "https://rubydoc.info/gems/mcp";
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|||
spec.metadata["homepage_uri"] = spec.homepage
|
||||
spec.metadata["source_code_uri"] = spec.homepage
|
||||
spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
|
||||
spec.metadata["documentation_uri"] = "https://rubydoc.info/gems/mcp"
|
||||
|
||||
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
||||
%x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
||||
|
|
|
|||
Loading…
Reference in a new issue