Merge pull request #181 from jonathanhefner/generate-api-docs

Add API documentation with GitHub Pages deployment
This commit is contained in:
Koichi ITO 2025-11-27 12:54:46 +09:00 • committed by GitHub
commit 00392b660d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 202 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -940,3 +940,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
View 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
View 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
View 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
View 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>

View file

@ -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)/}) }