Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lib/generators/docs_kit/install/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,17 @@ def add_routes
# bundled. A site opts in by adding `gem "mcp"` and uncommenting these. POST
# speaks JSON-RPC; GET/DELETE 405 (read-only, stateless — no SSE session).
# `route` prepends, so drawing `match` before `post` leaves `post` on top.
#
# Guarded on the endpoint (route_present?), NOT on Thor's byte-identical
# skip: a site that opted in has LIVE routes in its own style (an
# `, as: :mcp` suffix, single quotes) which never byte-match the commented
# template — plain `route` would re-inject the scaffold on every --sync.
# Found dogfooding 1.0.3 into pgbus + phlex-reactive.
def add_mcp_route
if route_present?(%(post "/mcp" => "docs_kit/mcp#create"))
return say_status(:identical, "route /mcp (already drawn or scaffolded)", :blue)
end

route %(# match "/mcp" => "docs_kit/mcp#method_not_allowed", via: %i[get delete])
route %(# post "/mcp" => "docs_kit/mcp#create")
route %(# Add your docs to an agent over MCP (needs `gem "mcp"`):)
Expand Down
19 changes: 19 additions & 0 deletions spec/generators/install_generator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,25 @@ def capture_stream
expect(routes).to include(%(# match "/mcp" => "docs_kit/mcp#method_not_allowed", via: %i[get delete]))
end

it "does not re-inject the commented MCP scaffold when the site has LIVE /mcp routes" do
# A site that opted in (uncommented, in its own style — an `, as: :mcp`
# suffix) must not accumulate the commented scaffold on every --sync run.
# Found dogfooding 1.0.3 into pgbus + phlex-reactive.
write("config/routes.rb", <<~ROUTES)
Rails.application.routes.draw do
post "/mcp" => "docs_kit/mcp#create", as: :mcp
match "/mcp" => "docs_kit/mcp#method_not_allowed", via: %i[get delete]
end
ROUTES

run_generator(sync: true)

routes = read("config/routes.rb")
expect(routes).not_to include(%(# post "/mcp"))
expect(routes).not_to include(%(# match "/mcp"))
expect(routes.scan(%r{docs_kit/mcp#create}).size).to eq(1)
end

it "draws /docs/search ABOVE docs/:doc so it isn't swallowed as :doc" do
routes = read("config/routes.rb")

Expand Down
Loading