Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@kosmoz
Copy link
Contributor

@kosmoz kosmoz commented Sep 25, 2025

This PR adds search and fetch tools to the MCP server, which should make it compatible with ChatGPT Deep Research (https://platform.openai.com/docs/mcp).

The search tool makes a naive substring search for all page contents and returns the matching pages.

The fetch tool is identical to the existing get_docs_by_id tool. The tool callback function of the get_docs_by_id tool was extracted in order to make it reusable.

High-level PR Summary

This PR adds two new tools (search and fetch) to the MCP (Model Context Protocol) server to improve compatibility with ChatGPT Deep Research. The search tool performs a basic substring search across page contents and returns matching pages, while the fetch tool serves as an alias for the existing get_docs_by_id tool. The implementation extracts the callback function from get_docs_by_id to a separate reusable function that can be used by both tools. The PR also includes the necessary OpenAPI specification updates to document these new tools.

⏱️ Estimated Review Time: 15-30 minutes

💡 Review Order Suggestion
Order File Path
1 docs/src/app/api/internal/[transport]/route.ts

Need help? Join our Discord


Important

Add search and fetch tools to MCP server for enhanced ChatGPT compatibility, with fetch reusing get_docs_by_id functionality.

  • Tools:
    • Add search tool to perform substring search on documentation pages.
    • Add fetch tool, identical to get_docs_by_id, for retrieving documentation by ID.
  • Functions:
    • Extract getDocsById function for reuse by fetch tool.
  • Integration:
    • Integrate search and fetch tools into MCP server handler in route.ts.

This description was created by Ellipsis for b1dd548. You can customize this summary. It will automatically update as commits are pushed.

Summary by CodeRabbit

  • New Features

    • Added a search tool to find documentation by title, description, or content, returning structured results.
    • Added a fetch tool to retrieve documentation by ID via the new retrieval flow.
  • Improvements

    • More resilient content loading with multiple fallback paths.
    • Enhanced API page summaries with extracted OpenAPI details when available.
    • Clearer error responses and consistent behavior even when some reads fail.
    • Unified listing and fetching for more reliable results.

@vercel
Copy link

vercel bot commented Sep 25, 2025

@kosmoz is attempting to deploy a commit to the Stack Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 25, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Implements a new exported function getDocsById({ id }) with multi-path content resolution and OpenAPI extraction; refactors MCP handlers to use this function, adds search and fetch tools, and adds runtime fallbacks and structured success/error CallToolResult responses.

Changes

Cohort / File(s) Summary
Docs API tools and routing
docs/src/app/api/internal/[transport]/route.ts
Added exported getDocsById({ id }) : Promise<CallToolResult> with multi-path reads (content/{path}, content/docs/{path}, content/api/{path}) and try/catch fallbacks; introduced extractOpenApiDetails(content, page) usage for EnhancedAPIPage; refactored MCP handler to delegate get_docs_by_id to getDocsById, wired list_available_docs to new flow; added MCP tools search (title/description/content scan) and fetch (delegates to getDocsById) and extended capabilities descriptor with parameter schemas.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Client
  participant Route as Internal Route
  participant Tools as MCP Tools
  participant Loader as getDocsById
  participant FS as FileSystem
  participant Parser as OpenAPI Parser

  Client->>Route: call tool "fetch" with { id }
  Route->>Tools: dispatch fetch
  Tools->>Loader: getDocsById({ id })
  rect rgba(220,235,255,0.35)
    note over Loader,FS: Multi-path resolution (primary + fallbacks)
    Loader->>FS: read content/{path}
    alt Not found / error
      Loader->>FS: read content/docs/{path}
      alt Not found / error
        Loader->>FS: read content/api/{path}
      end
    end
  end
  alt API page with EnhancedAPIPage
    Loader->>Parser: extractOpenApiDetails(content, page)
    alt Parse success
      Parser-->>Loader: OpenAPI summary
      Loader-->>Tools: formatted OpenAPI result
    else Parse fails
      Loader-->>Tools: formatted fallback API text
    end
  else Non-API page
    Loader-->>Tools: title + description + content
  end
  Tools-->>Route: CallToolResult
  Route-->>Client: response (success or isError)
Loading
sequenceDiagram
  autonumber
  actor Client
  participant Route
  participant Tools as MCP Tools
  participant Index as Page Index

  Client->>Route: call tool "search" with query
  Route->>Tools: dispatch search
  Tools->>Index: match by title/description/content
  Index-->>Tools: results[]
  Tools-->>Route: structured results[]
  Route-->>Client: results[]
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

I hop through folders, sniff the trail,
Three paths to check when one should fail,
I fetch the spec, and parse with care,
I surface text when parsers err.
Carrots, docs, and cozy code 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title clearly and concisely summarizes the primary change of adding search and fetch tools to the MCP server for improved ChatGPT compatibility, which aligns with the changes in the pull request.
Description Check ✅ Passed The pull request description includes the required CONTRIBUTING.md comment and provides a clear summary of the changes, tool implementations, and integration details, including a high-level summary and optional details, meeting the repository’s template requirements.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4ad88a5 and f397470.

📒 Files selected for processing (1)
  • docs/src/app/api/internal/[transport]/route.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer ES6 Map over Record when representing key–value collections

Files:

  • docs/src/app/api/internal/[transport]/route.ts
🧬 Code graph analysis (1)
docs/src/app/api/internal/[transport]/route.ts (1)
apps/dashboard/src/app/(main)/wizard-congrats/posthog.tsx (1)
  • PostHog (8-32)
🪛 Biome (2.1.2)
docs/src/app/api/internal/[transport]/route.ts

[error] 227-227: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: check_prisma_migrations (22.x)
  • GitHub Check: lint_and_build (latest)
  • GitHub Check: docker
  • GitHub Check: all-good
  • GitHub Check: setup-tests
  • GitHub Check: build (22.x)
  • GitHub Check: build (22.x)
  • GitHub Check: Vercel Agent Review
  • GitHub Check: Security Check
🔇 Additional comments (5)
docs/src/app/api/internal/[transport]/route.ts (5)

7-7: LGTM!

The import is correctly typed and necessary for the new CallToolResult return types throughout the file.


14-96: LGTM!

The refactored signature with Promise<CallToolResult> return type and the comprehensive error handling provide proper structure for the MCP tool responses.


238-243: LGTM!

The refactoring to delegate to the extracted getDocsById function improves code reusability and maintainability.


314-319: LGTM!

The fetch tool correctly delegates to getDocsById, providing the alias functionality needed for ChatGPT Deep Research compatibility.


351-378: LGTM!

The capabilities descriptor properly documents the new search and fetch tools with correct parameter schemas and descriptions.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@recurseml recurseml bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review by RecurseML

🔍 Review performed on 6bf092a..b1dd548

  Severity     Location     Issue     Delete  
Low docs/src/app/api/internal/[transport]/route.ts:296 Single-word API field 'url' technically conforms to both camelCase and snake_case conventions

@zeropath-ai
Copy link

zeropath-ai bot commented Sep 25, 2025

Some new issue(s) might be present. Please use the following link(s) to view them:

Additionally, the following low severity issue(s) were found:

https://zeropath.com/app/issues/2bd9a525-5fa1-49df-9722-9996bf21882f

Reply to this PR with @zeropath-ai followed by a description of what change you want and we'll auto-submit a change to this PR to implement it.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/src/app/api/internal/[transport]/route.ts (1)

248-279: Fix Biome error: Unexpected empty object pattern in handler arg (second occurrence).
Same as above.

-      async ({}) => {
+      async () => {
🧹 Nitpick comments (9)
docs/src/app/api/internal/[transport]/route.ts (9)

7-7: Type import is appropriate. Consider typing helper returns explicitly.
Import looks good. Recommend annotating extractOpenApiDetails to return Promise for consistency with getDocsById.

Apply this diff to the function signature at Lines 14-17:

-async function extractOpenApiDetails(
+async function extractOpenApiDetails(
   content: string,
   page: { data: { title: string, description?: string } },
-) {
+): Promise<CallToolResult> {

14-96: Harden OpenAPI helper and path handling (optional).

  • Consider resolving specFile relative to a known root to avoid brittle relative paths.
  • Regex parsing of JSX props is brittle; OK as a stopgap, but document or add TODO to replace with a proper parser.

124-128: Avoid potential unhandled promise rejections from PostHog capture.
Prefix with void (or .catch(() => {})) since posthog-node v4 methods are async.

-  nodeClient?.capture({
+  void nodeClient?.capture({
     event: "get_docs_by_id",
     properties: { id },
     distinctId: "mcp-handler",
   });

130-133: Mark not-found as error and include the requested id.
Improves client handling and observability.

-  if (!page) {
-    return { content: [{ type: "text", text: "Page not found." }] };
-  }
+  if (!page) {
+    return {
+      content: [{ type: "text", text: `Page not found: ${id}` }],
+      isError: true,
+    };
+  }

168-171: Deduplicate fallback paths to avoid content/docs/docs/...
If page.file.path already contains a docs/api prefix, this prevents broken double-prefixed attempts.

-    const altPaths = [
-      `content/docs/${page.file.path}`,
-      `content/api/${page.file.path}`,
-    ];
+    const altPaths = [
+      `content/docs/${page.file.path}`,
+      `content/api/${page.file.path}`,
+    ].filter((p) => p !== filePath);

349-376: Capabilities: add search/fetch looks good; consider aligning existing tool names.
Your newly added capability entries for search/fetch match the tool names. For consistency and discoverability, consider aligning earlier capability keys (listAvailableDocs, getDocById, getStackAuthSetupInstructions) to the actual registered tool names (list_available_docs, get_docs_by_id, get_stack_auth_setup_instructions).

If you decide to align, update the keys above accordingly (outside this hunk):

// In capabilities.tools:
list_available_docs: { /* ... */ },
get_docs_by_id: { /* ... */ },
get_stack_auth_setup_instructions: { /* ... */ },

Note: Verify @vercel/mcp-adapter and client expectations; some clients may use capabilities to resolve tools by key.


123-219: Minor content formatting consistency.
In several places, description may be undefined; consider using nullish coalescing to avoid “undefined” appearing in output.

Example change:

- text: `Title: ${page.data.title}\nDescription: ${page.data.description}\nContent:\n${content}`,
+ text: `Title: ${page.data.title}\nDescription: ${page.data.description ?? ''}\nContent:\n${content}`,

9-11: PostHog SDK best practices (non-blocking analytics).
Current usage is fine; optionally add a process-exit hook to flush/shutdown in long-lived processes, or use captureImmediate in serverless. Not blocking for this PR.


281-309: Use structuredContent for JSON results
MCP SDK doesn’t define a “json” content type. When CallToolResult supports structuredContent, return your { results } via a structuredContent field instead of embedding JSON in a text item; otherwise fall back to the existing content: [{ type: 'text', text: JSON.stringify({ results }) }].

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6bf092a and b1dd548.

📒 Files selected for processing (1)
  • docs/src/app/api/internal/[transport]/route.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer ES6 Map over Record when representing key–value collections

Files:

  • docs/src/app/api/internal/[transport]/route.ts
🪛 Biome (2.1.2)
docs/src/app/api/internal/[transport]/route.ts

[error] 227-227: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Security Check

@CLAassistant
Copy link

CLAassistant commented Sep 25, 2025

CLA assistant check
All committers have signed the CLA.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
docs/src/app/api/internal/[transport]/route.ts (3)

73-81: Mark OpenAPI spec read failure as an error.

Return includes error text but lacks isError:true, making it harder for clients to detect failures.

Apply this diff:

         return {
           content: [
             {
               type: "text" as const,
               text: errorText,
             },
           ],
+          isError: true,
         };

148-165: Avoid 'undefined' in responses: normalize description field.

Some responses interpolate page.data.description without a fallback; template strings will print “undefined”.

Apply this diff:

-              text: `Title: ${page.data.title}\nDescription: ${page.data.description}\nContent:\n${content}`,
+              text: `Title: ${page.data.title}\nDescription: ${page.data.description ?? ""}\nContent:\n${content}`,
-            text: `Title: ${page.data.title}\nDescription: ${page.data.description}\nContent:\n${content}`,
+            text: `Title: ${page.data.title}\nDescription: ${page.data.description ?? ""}\nContent:\n${content}`,
-                text: `Title: ${page.data.title}\nDescription: ${page.data.description}\nContent:\n${content}`,
+                text: `Title: ${page.data.title}\nDescription: ${page.data.description ?? ""}\nContent:\n${content}`,
-                text: `Title: ${page.data.title}\nDescription: ${page.data.description}\nContent:\n${content}`,
+                text: `Title: ${page.data.title}\nDescription: ${page.data.description ?? ""}\nContent:\n${content}`,
-          text: `Title: ${page.data.title}\nDescription: ${page.data.description}\nError: Could not read file at any of the attempted paths: ${filePath}, ${altPaths.join(", ")}`,
+          text: `Title: ${page.data.title}\nDescription: ${page.data.description ?? ""}\nError: Could not read file at any of the attempted paths: ${filePath}, ${altPaths.join(", ")}`,

Also applies to: 183-201, 209-217


112-113: Use strict inequality.

Minor style/consistency improvement.

Apply this diff:

-    return !(v.slugs[0] == "API-Reference");
+    return v.slugs[0] !== "API-Reference";
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b1dd548 and 4ad88a5.

📒 Files selected for processing (1)
  • docs/src/app/api/internal/[transport]/route.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Prefer ES6 Map over Record when representing key–value collections

Files:

  • docs/src/app/api/internal/[transport]/route.ts
🪛 Biome (2.1.2)
docs/src/app/api/internal/[transport]/route.ts

[error] 227-227: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Security Check
🔇 Additional comments (4)
docs/src/app/api/internal/[transport]/route.ts (4)

7-7: Type import for CallToolResult is correct.

Good: aligns return types for tool handlers.


315-319: Fetch tool delegation looks good.

Delegating to getDocsById keeps behavior consistent and reuses logic.


227-227: Fix Biome error: replace empty object pattern parameter.

This triggers lint/correctness/noEmptyPattern and will fail CI.

Apply this diff:

-      async ({}) => {
+      async () => {

288-300: Prevent runtime TypeError in search (optional chaining misuse, missing fields).

description and content may be undefined; current chaining still calls .includes on undefined.

Apply this diff for robust, case‑insensitive search:

-      async ({ query }) => {
-        const q = query.toLowerCase();
-        const results = allPages
-          .filter(
-            (page) =>
-              page.data.title.toLowerCase().includes(q) ||
-              page.data.description?.toLowerCase().includes(q) ||
-              page.data.content.toLowerCase().includes(q),
-          )
-          .map((page) => ({
-            id: page.url,
-            title: page.data.title,
-            url: page.url,
-          }));
+      async ({ query }) => {
+        const q = query.toLowerCase();
+        const results = allPages
+          .filter((page) => {
+            const title = (page.data.title ?? "").toLowerCase();
+            const description = (page.data.description ?? "").toLowerCase();
+            const content = (page.data.content ?? "").toLowerCase();
+            return title.includes(q) || description.includes(q) || content.includes(q);
+          })
+          .map((page) => ({
+            id: page.url,
+            title: page.data.title ?? "",
+            url: page.url,
+          }));

Optional (nice-to-have):

  • Limit results (e.g., .slice(0, 50)) to keep responses small.
  • Capture telemetry: nodeClient?.capture({ event: "search", properties: { q }, distinctId: "mcp-handler" });

@N2D4 N2D4 requested a review from madster456 October 8, 2025 23:11
@N2D4
Copy link
Contributor

N2D4 commented Oct 8, 2025

Thanks so much! Can you review this @madster456 ?

@vercel
Copy link

vercel bot commented Oct 10, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
stack-backend Ready Ready Preview Comment Nov 17, 2025 3:17pm
stack-dashboard Ready Ready Preview Comment Nov 17, 2025 3:17pm
stack-demo Ready Ready Preview Comment Nov 17, 2025 3:17pm
stack-docs Ready Ready Preview Comment Nov 17, 2025 3:17pm

@N2D4 N2D4 enabled auto-merge (squash) October 10, 2025 21:11
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is being reviewed by Cursor Bugbot

Details

You are on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Copy link
Collaborator

@madster456 madster456 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the added tools! I went ahead and made some small changes, and updated our MCP as it was failing to deliver pages to chats. Should all be working now. Tested MCP locally, and with ChatGPT deep search. Looks good to go.

@N2D4 N2D4 merged commit bc57d0d into stack-auth:dev Nov 17, 2025
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants