Skip to content

Commit 00392b6

Browse files
authored
Merge pull request #181 from jonathanhefner/generate-api-docs
Add API documentation with GitHub Pages deployment
2 parents 6bb96dd + 281c334 commit 00392b6

File tree

9 files changed

+202
-0
lines changed

9 files changed

+202
-0
lines changed

.github/workflows/ci.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,14 @@ jobs:
3131
ruby-version: 3.2 # Specify the oldest supported Ruby version.
3232
bundler-cache: true
3333
- run: bundle exec rake rubocop
34+
35+
yard:
36+
runs-on: ubuntu-latest
37+
name: YARD Documentation
38+
steps:
39+
- uses: actions/checkout@v5
40+
- uses: ruby/setup-ruby@v1
41+
with:
42+
ruby-version: 3.2 # Specify the oldest supported Ruby version.
43+
bundler-cache: true
44+
- run: bundle exec yard --no-output

.github/workflows/release.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,35 @@ jobs:
2323
bundler-cache: true
2424
ruby-version: 3.4
2525
- uses: rubygems/release-gem@v1
26+
27+
publish_gh_pages:
28+
if: github.repository_owner == 'modelcontextprotocol'
29+
name: Publish Documentation to GitHub Pages
30+
runs-on: ubuntu-latest
31+
needs: [publish_gem]
32+
33+
permissions:
34+
contents: write
35+
36+
steps:
37+
- uses: actions/checkout@v5
38+
with:
39+
fetch-depth: 0 # Fetch all history for all branches and tags
40+
41+
- name: Configure Git
42+
run: |
43+
git config --global user.name "github-actions[bot]"
44+
git config --global user.email "github-actions[bot]@users.noreply.github.com"
45+
46+
- name: Get version tag
47+
id: version
48+
run: |
49+
git fetch --tags
50+
TAG=$(git describe --tags --exact-match HEAD)
51+
echo "tag=${TAG}" >> $GITHUB_OUTPUT
52+
53+
- name: Generate GitHub Pages
54+
run: ./bin/generate-gh-pages.sh ${{ steps.version.outputs.tag }}
55+
56+
- name: Push to gh-pages
57+
run: git push origin gh-pages

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ gem "activesupport"
1717
gem "debug"
1818
gem "rake", "~> 13.0"
1919
gem "sorbet-static-and-runtime"
20+
gem "yard", "~> 0.9"
21+
gem "yard-sorbet", "~> 0.9"
2022

2123
group :test do
2224
gem "faraday", ">= 2.0"

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,3 +940,8 @@ The client provides a wrapper class for tools returned by the server:
940940
- `MCP::Client::Tool` - Represents a single tool with its metadata
941941

942942
This class provides easy access to tool properties like name, description, input schema, and output schema.
943+
944+
## Documentation
945+
946+
- [SDK API documentation](https://rubydoc.info/gems/mcp)
947+
- [Model Context Protocol documentation](https://modelcontextprotocol.io)

bin/generate-gh-pages.sh

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
#!/bin/bash
2+
set -e
3+
4+
# Generates versioned documentation links and commits to gh-pages branch
5+
#
6+
# PURPOSE:
7+
# This script generates a landing page with links to API documentation on
8+
# RubyDoc.info for a specific version tag. This script is invoked by the
9+
# publish-gh-pages job in the GitHub Actions workflow
10+
# (.github/workflows/release.yml) when a release is published.
11+
#
12+
# HOW IT WORKS:
13+
# - Creates isolated git worktrees for the specified tag and gh-pages branch
14+
# - Copies static Jekyll template files from docs/
15+
# - Generates _data/versions.yml with list of versions
16+
# - Commits changes to gh-pages (does not push automatically)
17+
#
18+
# WORKFLOW:
19+
# 1. Run this script with a tag name: `generate-gh-pages.sh v1.2.3`
20+
# 2. Script generates docs and commits to local gh-pages branch
21+
# 3. Push gh-pages branch to deploy: `git push origin gh-pages`
22+
23+
# Parse semantic version from tag name (ignoring arbitrary prefixes)
24+
if [[ "${1}" =~ ([0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?)$ ]]; then
25+
VERSION="v${BASH_REMATCH[1]}"
26+
else
27+
echo "Error: Must specify a tag name that contains a valid semantic version"
28+
echo "Usage: ${0} <tag-name>"
29+
echo "Examples:"
30+
echo " ${0} 1.2.3"
31+
echo " ${0} v2.0.0-rc.1"
32+
exit 1
33+
fi
34+
35+
TAG_NAME="${1}"
36+
REPO_ROOT="$(git rev-parse --show-toplevel)"
37+
38+
echo "Generating documentation for tag: ${TAG_NAME}"
39+
40+
# Create temporary directories for both worktrees
41+
WORKTREE_DIR=$(mktemp -d)
42+
GHPAGES_WORKTREE_DIR=$(mktemp -d)
43+
44+
# Set up trap to clean up both worktrees on exit
45+
trap 'git worktree remove --force "${WORKTREE_DIR}" 2>/dev/null || true; \
46+
git worktree remove --force "${GHPAGES_WORKTREE_DIR}" 2>/dev/null || true' EXIT
47+
48+
echo "Creating worktree for ${TAG_NAME}..."
49+
git worktree add --quiet "${WORKTREE_DIR}" "${TAG_NAME}"
50+
51+
# Check if gh-pages branch exists
52+
if git show-ref --verify --quiet refs/heads/gh-pages; then
53+
echo "Creating worktree for existing gh-pages branch..."
54+
git worktree add --quiet "${GHPAGES_WORKTREE_DIR}" gh-pages
55+
elif git ls-remote --exit-code --heads origin gh-pages > /dev/null 2>&1; then
56+
echo "Creating worktree for gh-pages branch from remote..."
57+
git worktree add --quiet "${GHPAGES_WORKTREE_DIR}" -b gh-pages origin/gh-pages
58+
else
59+
echo "Creating worktree for new orphan gh-pages branch..."
60+
git worktree add --quiet --detach "${GHPAGES_WORKTREE_DIR}"
61+
git -C "${GHPAGES_WORKTREE_DIR}" checkout --orphan gh-pages
62+
git -C "${GHPAGES_WORKTREE_DIR}" rm -rf . > /dev/null 2>&1 || true
63+
fi
64+
65+
# Change to gh-pages worktree
66+
cd "${GHPAGES_WORKTREE_DIR}"
67+
68+
# Determine if this tag is the latest version
69+
echo "Determining if ${VERSION} is the latest version..."
70+
71+
# Get all existing version tags from the repository (reverse sorted, newest first)
72+
ALL_VERSIONS=$(
73+
git -C "${REPO_ROOT}" tag --list | \
74+
sed -nE 's/^[^0-9]*([0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?)$/v\1/p' | \
75+
sort -Vr
76+
)
77+
78+
# Get the latest version from all version tags
79+
LATEST_VERSION=$(echo "${ALL_VERSIONS}" | head -n 1)
80+
81+
if [ "${VERSION}" = "${LATEST_VERSION}" ]; then
82+
echo "${VERSION} is the latest version"
83+
else
84+
echo "${VERSION} is not the latest version (latest is ${LATEST_VERSION})"
85+
fi
86+
87+
# Update custom documentation for latest version
88+
if [ "${VERSION}" = "${LATEST_VERSION}" ]; then
89+
echo "Updating custom documentation..."
90+
91+
# Clean up old custom docs from gh-pages root
92+
echo "Cleaning gh-pages root..."
93+
git ls-tree --name-only HEAD | xargs -r git rm -rf
94+
95+
# Copy custom docs from docs/ directory
96+
echo "Copying custom docs from ${WORKTREE_DIR}/docs/..."
97+
cp -r "${WORKTREE_DIR}/docs/." "${GHPAGES_WORKTREE_DIR}/"
98+
fi
99+
100+
# Generate version data for Jekyll
101+
echo "Generating _data/versions.yml..."
102+
mkdir -p _data
103+
echo "${ALL_VERSIONS}" | sed 's/^v/- /' > _data/versions.yml
104+
105+
# Stage all changes
106+
git add .
107+
108+
# Commit if there are changes
109+
if git diff --staged --quiet; then
110+
echo "No changes to commit"
111+
else
112+
echo "Committing documentation for ${VERSION}..."
113+
git commit -m "Add ${VERSION} docs"
114+
115+
echo "Documentation committed to gh-pages branch!"
116+
echo "Push to remote to deploy to GitHub Pages"
117+
fi
118+
119+
echo "Done!"

docs/_config.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Use package name as site title
2+
title: "MCP Ruby SDK"
3+
4+
# Include generated files and directories which may start with underscores
5+
include:
6+
- "_*"

docs/index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
# Empty Jekyll front matter to enable Liquid templating (see {{ ... }} below)
3+
---
4+
5+
{% for version in site.data.versions -%}
6+
- [v{{ version }}](https://rubydoc.info/gems/mcp/{{ version }})
7+
{% endfor %}

docs/latest/index.html

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
# Empty Jekyll front matter to enable Liquid templating (see {{ ... }} below)
3+
---
4+
5+
<!DOCTYPE html>
6+
<html>
7+
<head>
8+
<meta charset="utf-8">
9+
<title>Redirecting to latest documentation...</title>
10+
<meta http-equiv="refresh" content="0; url=https://rubydoc.info/gems/mcp">
11+
<link rel="canonical" href="https://rubydoc.info/gems/mcp">
12+
</head>
13+
<body>
14+
<p>Redirecting to <a href="https://rubydoc.info/gems/mcp">latest documentation</a>...</p>
15+
<script>
16+
window.location.href = "https://rubydoc.info/gems/mcp";
17+
</script>
18+
</body>
19+
</html>

mcp.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
2020
spec.metadata["homepage_uri"] = spec.homepage
2121
spec.metadata["source_code_uri"] = spec.homepage
2222
spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
23+
spec.metadata["documentation_uri"] = "https://rubydoc.info/gems/mcp"
2324

2425
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
2526
%x(git ls-files -z).split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }

0 commit comments

Comments
 (0)