fix(mcp): return owner's own private prompts from get_prompt + accept category name/slug#1215
fix(mcp): return owner's own private prompts from get_prompt + accept category name/slug#1215fawadafr wants to merge 2 commits into
Conversation
Previously the MCP save tools matched `category` by exact slug only and
silently dropped any unrecognized value, so prompts were created with no
category and no feedback. Clients also had no way to discover valid slugs:
search_prompts exposed only the category name, and there was no listing tool.
- Add `list_categories` tool returning {name, slug, description, promptCount}
- Resolve category by slug, name, or slugified-name (forgiving match)
- Return a `warning` when a category is provided but unmatched, instead of
failing silently — naming the valid slugs
- Expose `categorySlug` in search_prompts and the save responses for round-trip
- Unit-test the matcher (findCategoryMatch) for the resolution cases
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SxPKXfHMaqgtmitAQC1Zjx
get_prompt hard-filtered `isPrivate: false`, so the authenticated owner got "Prompt not found" for their own private prompts — while search_prompts and get_skill already include the owner's private entries. This blocked reading a private prompt's full content (e.g. to score it against an eval). Extract buildPromptVisibilityFilter() (public OR owner's-own-private) and use it in both get_prompt and get_skill, replacing the duplicated inline blocks. Add unit tests for the helper incl. a regression check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DL6AEgE5FypVamGVTZhS8a
📝 WalkthroughWalkthroughAdds MCP Category Support
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/pages/api/mcp.ts`:
- Around line 1424-1445: The list_categories response is leaking hidden prompt
volume through the unfiltered promptCount value. In the category query and
mapping inside the list_categories handler in mcp.ts, either remove promptCount
from the returned category payload or compute it using the same
caller-visibility constraints used by the prompt lookup tools so only visible
prompts are counted.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: f5570d71-a251-498e-891e-61513e2c9013
📒 Files selected for processing (2)
src/__tests__/api/mcp-handler.test.tssrc/pages/api/mcp.ts
| const categories = await db.category.findMany({ | ||
| orderBy: [{ order: "asc" }, { name: "asc" }], | ||
| select: { | ||
| name: true, | ||
| slug: true, | ||
| description: true, | ||
| _count: { select: { prompts: true } }, | ||
| }, | ||
| }); | ||
|
|
||
| return { | ||
| content: [ | ||
| { | ||
| type: "text" as const, | ||
| text: JSON.stringify({ | ||
| count: categories.length, | ||
| categories: categories.map((c) => ({ | ||
| name: c.name, | ||
| slug: c.slug, | ||
| description: c.description || null, | ||
| promptCount: c._count.prompts, | ||
| })), |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify the Category -> Prompt relation and existing count/filter test coverage.
fd -a 'schema.prisma$' . -x sed -n '/model Category/,/}/p' {}
fd -a 'schema.prisma$' . -x sed -n '/model Prompt/,/}/p' {}
rg -n -C3 'list_categories|_count:\s*\{\s*select:\s*\{\s*prompts|promptCount|buildPromptVisibilityFilter' src/pages/api/mcp.ts src/__tests__/api/mcp-handler.test.tsRepository: f/prompts.chat
Length of output: 12962
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Check whether this repo already uses relation-count filtering elsewhere.
rg -n '_count:\s*\{\s*select:\s*\{\s*[^}]+where:' srcRepository: f/prompts.chat
Length of output: 152
Filter promptCount by caller visibility, or drop it. list_categories currently counts every related prompt, so callers can infer hidden prompt volume from category stats. Use the same visibility filter as the prompt lookup tools.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/pages/api/mcp.ts` around lines 1424 - 1445, The list_categories response
is leaking hidden prompt volume through the unfiltered promptCount value. In the
category query and mapping inside the list_categories handler in mcp.ts, either
remove promptCount from the returned category payload or compute it using the
same caller-visibility constraints used by the prompt lookup tools so only
visible prompts are counted.
Two small, self-contained fixes to the MCP server (
src/pages/api/mcp.ts), each with tests.1.
get_prompthides owners' own private promptsget_prompthard-filteredisPrivate: false, so an authenticated owner got "Prompt not found" when fetching their own private prompt — even thoughget_skillandsearch_promptsalready surface owner-private entries. This was an inconsistency between the two read paths.Extracted a shared
buildPromptVisibilityFilter(authenticatedUser)→isPrivate:false OR (isPrivate:true AND authorId === me)for authenticated callers, public-only otherwise — and applied it to bothget_promptandget_skillso they stay in sync.2.
save_prompt/save_skillsilently drop unrecognized categoriesCategory was resolved by exact slug only (
findUnique({ where: { slug } })); a category name, a differently-cased slug, orcode_reviewvscode-reviewwas silently ignored, creating an uncategorized prompt with no feedback.findCategoryMatch()/resolveCategory()match by slug → name → slugified-name (all case-insensitive).warninglisting valid slugs, instead of silently dropping the value.list_categoriestool so clients can discover valid slugs before saving.categorySlugtosearch_promptsand to thesave_*success payloads so a category can be round-tripped.Tests
src/__tests__/api/mcp-handler.test.tsadds unit coverage forfindCategoryMatch(slug / name / slugify / whitespace / no-match) andbuildPromptVisibilityFilter(including a regression test that an owner's filter does not hard-exclude their private prompts). All 17 tests pass.No schema changes, no new dependencies, no breaking changes to existing tool signatures (the
categoryarg now also accepts a name; previously-valid slugs behave identically).🤖 Generated with Claude Code
Implemented MCP server fixes around prompt visibility and category handling.
get_promptso authenticated owners can access their own private prompts, while unauthenticated users still only see public prompts.get_promptandget_skill.save_promptandsave_skillto resolve by slug, name, or slugified name in a case-insensitive way.list_categoriesfor client-side category lookup.categorySluginsearch_promptsand save success responses so category values can round-trip.