Starting Prompt — Coordinating The MCP Port
Copy the template below, fill in the placeholders, and paste it to your AI agent as the starting prompt. It tells the agent to read this package, execute the porting playbook, and scaffold the tool set you want.
The bottom of this file has a worked example with every placeholder filled in — use it as a reference for what "good input" looks like.
How To Use This File
- Read the package once yourself so you know what the agent will be doing: README.md, 03_porting_playbook.md, 06_tooling_and_dependencies.md.
- Copy the
## Prompt Templatesection below into a new message for your agent. - Replace every
{{...}}placeholder with your real values. - Delete any section that does not apply (for example, "MCP Button / UI Placement" if you are API-only).
- Send the message. The agent will follow the playbook phases and report back at each phase boundary.
The {{REPEAT}} blocks are lists — duplicate the block once per resource, route, etc.
Prompt Template
You are helping me add a user-scoped MCP (Model Context Protocol) server to my Rails app so I can expose my resources to AI clients like Claude Desktop and Claude Code.
Before you write any code, read the full package at `docs/mcp/generic-mcp-feature-step-by-step/` (or wherever I dropped it). Specifically read in this order:
1. README.md
2. 01_architecture_and_connection_flow.md
3. 02_file_inventory.md
4. 03_porting_playbook.md
5. 04_tool_patterns.md
6. 05_security_ops_and_testing.md
7. 06_tooling_and_dependencies.md
Follow the phased porting playbook from 03_porting_playbook.md exactly. Stop at the end of each phase and summarize what you did and what you will do next before continuing.
## Project Context
- App name: {{APP_NAME}}
- Rails version: {{RAILS_VERSION}}
- Database: {{DATABASE}} (e.g. SQLite / PostgreSQL / MySQL)
- Auth stack: {{AUTH_STACK}} (e.g. Devise / Rails 8 built-in auth / custom)
- Actor model: {{ACTOR_MODEL}} (usually `User`; rename `user` / `user_context` in the generic templates if you use a different model)
- Authorization: {{AUTHZ_STACK}} (e.g. Pundit / inline / none)
- Does the app already have a `Current` attributes class? {{HAS_CURRENT_YES_OR_NO}}
- Production domain (for the MCP URL documentation): {{PROD_DOMAIN}}
## Resources To Expose Through MCP
For each resource, I want the CRUD actions I list. Skip any action I do not list.
{{REPEAT for each resource}}
### Resource: {{ResourceModelName}}
- Association on the actor: `{{actor}}.{{association_name}}` (e.g. `user.items`)
- Permission key: `{{permission_key}}` (lowercase plural, matches `mcp_domain`)
- Namespace: `Mcp::Tools::{{ResourceNamespace}}`
- Tool folder: `app/models/mcp/tools/{{folder_name}}/`
- Attributes to permit on create/update: `{{attr1}}`, `{{attr2}}`, `{{attr3}}`
- Required attributes on create: `{{required_attr}}`
- Enum fields (if any): `{{field}}` in [{{value1}}, {{value2}}, {{value3}}]
- Default status on create (if any): `{{default_status}}`
- Actions to implement (check all that apply):
- [ ] list_{{singular}} (read)
- [ ] get_{{singular}} (read)
- [ ] create_{{singular}} (create)
- [ ] update_{{singular}} (update)
- [ ] delete_{{singular}} (delete)
- Extra response fields to include in `get` / `create` / `update` output beyond the obvious ones: `{{extra_field}}`
- Special notes (soft delete, rich text, attachments, nested has_many, scopes to include): {{NOTES_OR_NONE}}
{{END REPEAT}}
## MCP Button / UI Placement
I want a visible entry point for users to manage their MCP tokens. Place it here:
- Primary entry point: {{WHERE_TO_PUT_PRIMARY_BUTTON}}
(e.g. "user dropdown menu in the top nav", "account settings sidebar under 'Integrations'", "dashboard card")
- Label: "{{BUTTON_LABEL}}" (e.g. "MCP Tokens", "AI Access", "Connect Claude")
- Icon: {{ICON_OR_NONE}} (e.g. heroicon name, none)
- Route name: `{{ROUTE_HELPER}}` (e.g. `mcp_settings_path`)
- Page copy / tagline shown above the token list: "{{PAGE_TAGLINE}}"
Design system hints:
- CSS framework: {{CSS_FRAMEWORK}} (e.g. Tailwind, Bootstrap, custom)
- Existing button component to reuse: {{BUTTON_COMPONENT_OR_PATH_OR_NONE}}
- Existing settings layout to reuse: {{SETTINGS_LAYOUT_OR_NONE}}
## Routes
Mount the MCP endpoint at:
- Rack mount: `mount Mcp::RackApp.new, at: "/mcp"` (keep this outside `authenticated` blocks)
- Token management nesting: `{{ROUTES_NAMESPACE}}` (e.g. `namespace :mcp, path: "settings/mcp"`)
- Must this be protected by an `authenticated :{{ACTOR_SYMBOL}}` block? {{YES_OR_NO}}
## Tests
- Test framework: {{TEST_FRAMEWORK}} (Minitest / RSpec)
- For each resource, generate tests covering the matrix in `05_security_ops_and_testing.md`:
- scope leak test (foreign user's id → not_found)
- validation failure returns text_response, not 500
- success creates an `Mcp::ActivityLog` row
- list tool includes IDs in output
## Constraints And Guardrails
- Do not add background job processing for activity logging — keep it synchronous as the package ships.
- Do not change rate limit defaults (60/min/token) without asking me.
- Do not enable `delete_*` tools unless I explicitly checked the delete box for a given resource.
- Default every permission checkbox on the new-token form to `true` (opt-out UX).
- The raw token must only appear once (flash after create or regenerate). Never store it.
- Every query inside a tool class must start from the user-scoped association. Reject any code that calls `{{ResourceModelName}}.where(user_id: ...)` directly.
- Use the exact naming conventions from `04_tool_patterns.md`: one tool per action, domain matches the permission key, `mcp_action` is one of `read|create|update|delete`.
- Do not generate a UI for the activity log unless I asked for it in this prompt.
## Deliverables, In Order
Report back after each of these checkpoints — do not silently continue past a checkpoint failure:
1. Phase 1–2 (runtime + context): models and migrations created, `bin/rails db:migrate` runs clean.
2. Phase 3 (endpoint wired): `POST /mcp/invalid-token` returns 401; `POST /mcp/<valid-token>` reaches the builder.
3. Phase 4 (builder + base tool): `tools/list` returns an empty array without error.
4. Phase 5 (first resource): the first resource's permitted tools appear in `tools/list` for a valid token; scoped queries confirmed.
5. Phase 6 (token UI): I can create, rename, regenerate, and revoke tokens from the UI, and the MCP button appears where I asked.
6. Phase 7 (tests): all test categories from section "Recommended Tests For A Fresh Export" pass.
7. Phase 8 (remaining resources): subsequent resources ported one at a time, same test coverage each time.
Between checkpoints, paste a short status message listing files created, files modified, and any decisions where you deviated from the package defaults.
Start with Phase 1 now.
Worked Example
Below is the same template, filled in for a fictional journal + tasks app called Kindle. Use it as a reference for level of detail.
You are helping me add a user-scoped MCP (Model Context Protocol) server to my Rails app so I can expose my resources to AI clients like Claude Desktop and Claude Code.
Before you write any code, read the full package at `docs/mcp/generic-mcp-feature-step-by-step/`. Specifically read in this order:
1. README.md
2. 01_architecture_and_connection_flow.md
3. 02_file_inventory.md
4. 03_porting_playbook.md
5. 04_tool_patterns.md
6. 05_security_ops_and_testing.md
7. 06_tooling_and_dependencies.md
Follow the phased porting playbook from 03_porting_playbook.md exactly. Stop at the end of each phase and summarize what you did and what you will do next before continuing.
## Project Context
- App name: Kindle
- Rails version: 8.0.1
- Database: PostgreSQL 16
- Auth stack: Devise (email + magic link)
- Actor model: User
- Authorization: Pundit
- Does the app already have a `Current` attributes class? Yes — `app/models/current.rb` already has `attribute :user`
- Production domain (for the MCP URL documentation): https://kindle.app
## Resources To Expose Through MCP
### Resource: JournalEntry
- Association on the actor: `user.journal_entries`
- Permission key: `journal_entries`
- Namespace: `Mcp::Tools::JournalEntries`
- Tool folder: `app/models/mcp/tools/journal_entries/`
- Attributes to permit on create/update: `title`, `body`, `mood`, `entry_date`
- Required attributes on create: `title`
- Enum fields: `mood` in [happy, neutral, sad, anxious, grateful]
- Default status on create: none (no status column)
- Actions to implement:
- [x] list_journal_entry (read)
- [x] get_journal_entry (read)
- [x] create_journal_entry (create)
- [x] update_journal_entry (update)
- [ ] delete_journal_entry (delete) — intentionally excluded; journals are append-only
- Extra response fields: `word_count` (computed), `entry_date` formatted as ISO 8601
- Special notes: `body` is an ActionText rich text field; use `body.to_plain_text` in responses and accept a `body_plain` input on create/update.
### Resource: Task
- Association on the actor: `user.tasks`
- Permission key: `tasks`
- Namespace: `Mcp::Tools::Tasks`
- Tool folder: `app/models/mcp/tools/tasks/`
- Attributes to permit on create/update: `title`, `description`, `status`, `due_date`, `priority`
- Required attributes on create: `title`
- Enum fields: `status` in [todo, doing, done, archived], `priority` in [low, medium, high]
- Default status on create: `todo`
- Actions to implement:
- [x] list_task (read)
- [x] get_task (read)
- [x] create_task (create)
- [x] update_task (update)
- [x] delete_task (delete)
- Extra response fields: `overdue?` (computed: due_date < today && status != done)
- Special notes: tasks belong to an optional `Project` via `project_id`. Expose `project_id` as an optional input on create/update; validate ownership with `user.projects.find_by(id: project_id)` before assignment.
## MCP Button / UI Placement
I want a visible entry point for users to manage their MCP tokens. Place it here:
- Primary entry point: account settings sidebar, under an "Integrations" heading, below the existing "Email Notifications" link
- Label: "AI Access (MCP)"
- Icon: heroicon `cpu-chip`
- Route name: `mcp_settings_path`
- Page copy / tagline shown above the token list: "Generate tokens to let Claude or other AI clients read and edit your Kindle data on your behalf."
Design system hints:
- CSS framework: Tailwind
- Existing button component to reuse: `app/components/button_component.rb` — use `variant: :primary` for "New token" and `variant: :ghost` for regenerate/revoke
- Existing settings layout to reuse: `app/views/layouts/settings.html.erb` — use `content_for(:settings_section, "AI Access")`
## Routes
- Rack mount: `mount Mcp::RackApp.new, at: "/mcp"` (already outside the `authenticated` block)
- Token management nesting: `namespace :mcp, path: "settings/mcp"`
- Must this be protected by an `authenticated :user` block? Yes — wrap the `namespace :mcp` block in `authenticated :user do ... end`
## Tests
- Test framework: Minitest (with `rack-test` for Rack tests)
- For each resource, generate tests covering the matrix in `05_security_ops_and_testing.md`:
- scope leak test
- validation failure returns text_response
- success creates `Mcp::ActivityLog` row
- list tool includes IDs
## Constraints And Guardrails
- Do not add background job processing for activity logging.
- Do not change rate limit defaults.
- Do not enable `delete_*` tools for JournalEntry.
- Default every permission checkbox on new-token form to `true`.
- Raw token appears only once via flash.
- Every tool query must start from `user.<association>`.
- One tool per action, domain matches permission key, `mcp_action` ∈ `read|create|update|delete`.
- Do not generate an activity log UI — I will add that later.
## Deliverables, In Order
Report back after each checkpoint:
1. Phase 1–2: models + migrations created, `bin/rails db:migrate` runs clean.
2. Phase 3: `POST /mcp/invalid` → 401; `POST /mcp/<valid>` reaches the builder.
3. Phase 4: `tools/list` returns `[]` without error.
4. Phase 5: JournalEntry tools appear first; scope leak test green.
5. Phase 6: token UI works, "AI Access (MCP)" link appears in settings sidebar.
6. Phase 7: full test matrix green for JournalEntry.
7. Phase 8: Task resource ported with same test coverage.
Between checkpoints, paste a short status message listing files created, files modified, and any decisions where you deviated from the package defaults.
Start with Phase 1 now.
What Makes A Good Filled-In Prompt
When you fill the template, the agent produces better output if you:
- Name attributes explicitly. "Permit name, status, notes" beats "permit reasonable fields." Agents default to over-permissive attribute lists otherwise.
- List enum values. Without them the agent invents
input_schemaenums that do not match your model. - Flag rich text / attachments / has_many / soft delete up front. These change the create/update tool shape. Surprising the agent halfway through a phase causes churn.
- Say where the MCP button goes before Phase 6. Otherwise the agent puts it somewhere generic and you rework the UI later.
- Be explicit about excluded actions. "[ ] delete" is not enough — say why it is excluded so the agent does not add it when generalizing patterns across resources.
- Pin the actor model name once.
User,Member,Account— the agent renames accessors across the whole package based on this.
What The Agent Should Not Need You To Specify
The package already decides these; do not override them without a reason:
- Token digest algorithm (SHA256) and storage shape
- Rate limit window (60s) and per-window cap (60)
- Transport (
StreamableHTTPTransport, stateless) - Response format helpers (
text_response,json_response,not_found_response) - Pagination per-page default (25)
- Sanitized keys in activity log (
/password|token|secret/i)
If any of those need to change, say so explicitly under "Constraints And Guardrails" and explain why.