Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ce745d8
switching search to MCP server - local only atm
madster456 Aug 22, 2025
2c909f5
filter out admin endpoints
madster456 Sep 22, 2025
28264f7
Update UI to support Server, Client, and Webhook types
madster456 Sep 22, 2025
7909549
Merge branch 'dev' into docs-updated_search
madster456 Sep 22, 2025
566e048
naming conventions
madster456 Sep 22, 2025
ac06c4a
Update endpoint to prod
madster456 Sep 22, 2025
435925a
small changes
madster456 Sep 23, 2025
9941d02
lint
madster456 Sep 23, 2025
26b9cf5
Merge dev into docs-updated_search
N2D4 Sep 25, 2025
93493bd
Merge dev into docs-updated_search
N2D4 Sep 27, 2025
7e220fb
Merge dev into docs-updated_search
N2D4 Sep 29, 2025
6dd9bf2
Merge dev into docs-updated_search
N2D4 Sep 30, 2025
e583748
Merge dev into docs-updated_search
N2D4 Oct 2, 2025
59eb2a6
Merge dev into docs-updated_search
N2D4 Oct 3, 2025
c5efbd4
Merge dev into docs-updated_search
N2D4 Oct 4, 2025
bcf0778
Merge dev into docs-updated_search
N2D4 Oct 7, 2025
c2b59c4
Merge dev into docs-updated_search
N2D4 Oct 8, 2025
5a18e48
Merge dev into docs-updated_search
N2D4 Oct 10, 2025
ab947be
Merge dev into docs-updated_search
N2D4 Oct 11, 2025
84b97e3
Merge dev into docs-updated_search
N2D4 Oct 12, 2025
06a59ed
Merge dev into docs-updated_search
N2D4 Oct 14, 2025
de59c32
Merge branch 'dev' into docs-updated_search
madster456 Oct 14, 2025
ef234ab
merge dev into docs-updated_search
madster456 Oct 21, 2025
fa21d1c
Update UI to match new docs w/o platform selection
madster456 Oct 21, 2025
8fcd98e
Merge branch 'dev' into docs-updated_search
madster456 Oct 22, 2025
4b63b6a
page-title lookups compare the anchor-stripped URL
madster456 Oct 22, 2025
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
125 changes: 125 additions & 0 deletions docs/src/app/api/internal/[transport]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,131 @@ const handler = createMcpHandler(
};
}
);
server.tool(
"search_docs",
"Search through all Stack Auth documentation including API docs, guides, and examples. Returns ranked results with snippets and relevance scores.",
{
search_query: z.string().describe("The search query to find relevant documentation"),
result_limit: z.number().optional().describe("Maximum number of results to return (default: 50)")
},
async ({ search_query, result_limit = 50 }) => {
nodeClient?.capture({
event: "search_docs",
Comment thread
madster456 marked this conversation as resolved.
properties: { search_query, result_limit },
distinctId: "mcp-handler",
});
Comment thread
madster456 marked this conversation as resolved.

const results = [];
const queryLower = search_query.toLowerCase().trim();

// Search through all pages
Comment thread
madster456 marked this conversation as resolved.
for (const page of allPages) {
// Skip admin API endpoints
if (page.url.startsWith('/api/admin/')) {
continue;
}
Comment thread
madster456 marked this conversation as resolved.

let score = 0;
const title = page.data.title || '';
const description = page.data.description || '';

// Title matching (highest priority)
if (title.toLowerCase().includes(queryLower)) {
if (title.toLowerCase() === queryLower) {
score += 100; // Exact match
} else if (title.toLowerCase().startsWith(queryLower)) {
score += 80; // Starts with
} else {
score += 60; // Contains
}
}

// Description matching
if (description.toLowerCase().includes(queryLower)) {
score += 40;
}
// TOC/heading matching
for (const tocItem of page.data.toc) {
if (typeof tocItem.title === 'string' && tocItem.title.toLowerCase().includes(queryLower)) {
score += 30;
}
}
Comment thread
madster456 marked this conversation as resolved.

// Content matching (try to read the actual file)
try {
const filePath = `content/${page.file.path}`;
const content = await readFile(filePath, "utf-8");
Comment thread
madster456 marked this conversation as resolved.
const textContent = content
Comment thread
madster456 marked this conversation as resolved.
.replace(/^---[\s\S]*?---/, '') // Remove frontmatter
.replace(/<[^>]*>/g, ' ') // Remove JSX tags
.replace(/\{[^}]*\}/g, ' ') // Remove JSX expressions
.replace(/```[a-zA-Z]*\n/g, ' ') // Remove code block markers
.replace(/```/g, ' ')
.replace(/`([^`]*)`/g, '$1') // Remove inline code backticks
.replace(/\[([^\]]*)\]\([^)]*\)/g, '$1') // Extract link text
.replace(/[#*_~]/g, '') // Remove markdown formatting
.replace(/\s+/g, ' ')
.trim();

if (textContent.toLowerCase().includes(queryLower)) {
score += 20;

// Find snippet around the match
const matchIndex = textContent.toLowerCase().indexOf(queryLower);
const start = Math.max(0, matchIndex - 50);
const end = Math.min(textContent.length, matchIndex + 100);
const snippet = textContent.slice(start, end);

results.push({
title,
description,
url: page.url,
score,
snippet: `...${snippet}...`,
type: page.url.startsWith('/api/') ? 'api' : 'docs'
});
} else if (score > 0) {
// Add without snippet if title/description matched
results.push({
title,
description,
url: page.url,
score,
snippet: description || title,
type: page.url.startsWith('/api/') ? 'api' : 'docs'
});
}
} catch {
// If file reading fails but we have title/description matches
if (score > 0) {
results.push({
title,
description,
url: page.url,
score,
snippet: description || title,
type: page.url.startsWith('/api/') ? 'api' : 'docs'
});
}
}
}

// Sort by score (highest first) and limit results
const sortedResults = results
.sort((a, b) => b.score - a.score)
.slice(0, result_limit);

const searchResultText = sortedResults.length > 0
? sortedResults.map(result =>
`Title: ${result.title}\nDescription: ${result.description}\nURL: ${result.url}\nType: ${result.type}\nScore: ${result.score}\nSnippet: ${result.snippet}\n`
).join('\n---\n')
: `No results found for "${search_query}"`;

return {
content: [{ type: "text", text: searchResultText }],
};
}
);
server.tool(
"get_docs_by_id",
"Use this tool to retrieve a specific Stack Auth Documentation page by its ID. It gives you the full content of the page so you can know exactly how to use specific Stack Auth APIs. Whenever using Stack Auth, you should always check the documentation first to have the most up-to-date information. When you write code using Stack Auth documentation you should reference the content you used in your comments.",
Expand Down
Loading
Loading