@kjadeja/open-featurebase-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@kjadeja/open-featurebase-mcpshow me the top 5 most-upvoted open posts without admin reply"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@kjadeja/open-featurebase-mcp
A Model Context Protocol (MCP) server I built for reading public Featurebase feedback boards from any MCP-compatible agent — Claude Code, Cursor, VS Code, others.
I built this for Remalt because I wanted my coding agent to be able to answer questions like "what have users been asking for that we haven't replied to?", "which promised fixes are stalled?", and "what's the most-upvoted unaddressed feedback this week?" without me copy-pasting from a browser tab.
The default board is the Remalt one, but it works against any public Featurebase board that exposes the same public listing + comment endpoints.
Install
Quickest path — npx
npx -y @kjadeja/open-featurebase-mcpThis runs the server directly without installing anything. Use this for one-off testing or to confirm the package works on your machine.
To install globally:
npm install -g @kjadeja/open-featurebase-mcpThen point any MCP client at the binary it adds to your PATH:
which open-featurebase-mcp
# /usr/local/bin/open-featurebase-mcp (macOS/Linux)
// or on Windows:
where open-featurebase-mcpConnecting an MCP client
The setup file format differs across clients — pick the one that matches yours.
Claude Code
The simplest setup is the CLI:
# Use the default Remalt board
claude mcp add --transport stdio --scope user featurebase -- npx -y @kjadeja/open-featurebase-mcp
# Or point at a different board
claude mcp add --transport stdio --scope user --env FEATUREBASE_BOARD_URL=https://example.featurebase.app featurebase -- npx -y @kjadeja/open-featurebase-mcpIf you prefer to keep it in a file, use .mcp.json in the project root with the mcpServers (note the camelCase) key:
{
"mcpServers": {
"featurebase": {
"command": "npx",
"args": ["-y", "@kjadeja/open-featurebase-mcp"],
"env": {
"FEATUREBASE_BOARD_URL": "https://itsremalt.featurebase.app"
}
}
}
}Cursor
Cursor uses .cursor/mcp.json in the project root, with the mcpServers key:
{
"mcpServers": {
"featurebase": {
"command": "npx",
"args": ["-y", "@kjadeja/open-featurebase-mcp"],
"env": {
"FEATUREBASE_BOARD_URL": "https://itsremalt.featurebase.app"
}
}
}
}VS Code (GitHub Copilot Chat or other MCP-aware extensions)
VS Code uses .vscode/mcp.json, with a top-level servers (not mcpServers) key:
{
"servers": {
"featurebase": {
"command": "npx",
"args": ["-y", "@kjadeja/open-featurebase-mcp"],
"env": {
"FEATUREBASE_BOARD_URL": "https://itsremalt.featurebase.app"
}
}
}
}Note: The three file formats are NOT interchangeable.
.vscode/mcp.jsonusesservers; Claude Code and Cursor usemcpServers. Copy the exact form above for your editor.
After editing the file, reload the editor so it picks up the new server. The seven tools below will appear in the MCP tools list.
Configuration
Env var | Default | Purpose |
|
| The public Featurebase board to read from. Optional — set this only if you want a different board. |
| (unset) | Comma-separated Featurebase user IDs considered team. Used for admin/customer classification. Optional. |
When team IDs matter
Most tools work without any team configuration — they read posts, comments, search, stats, batch-fetch, and user lookup without knowing who's on the team. Team IDs are only needed when you want to classify authors or detect stalled follow-ups:
Tool | Without team IDs | With team IDs |
| ✅ Works | ✅ Same result |
| ✅ Works; | ✅ Authors classified; engagement fields populated |
| ✅ Works | ✅ Authors classified |
| ✅ Works | ✅ Authors classified |
| ✅ Works | ✅ Same result |
| ✅ Works; | ✅ Same result |
| ❌ Throws | ✅ Filters posts |
| ⚠️ Returns empty with a | ✅ Returns stalled promises |
When a tool requires a team identity and none is configured, it errors out rather than silently fabricate customer / admin assignments. To enable the team-aware tools, either set FEATUREBASE_TEAM_USER_IDS=id1,id2,… in the env, or call find_featurebase_user with your name to discover IDs and pass them as teamUserIds per-call.
Practical prompts
These are the workflows I actually run. Paste them into Claude Code / Cursor after the MCP server is connected.
Daily triage
Show me the top 10 most-upvoted open posts that don't yet have an admin reply. For each one, summarize the request and quote the highest-voted customer comment.
This uses list_featurebase_posts(hasAdminReply=false, status="open", sortBy="upvotes:desc", teamUserIds=[…]) followed by get_featurebase_post for the top entries.
Find stalled follow-ups
Which posts have I (the team) replied to, the customer replied after me, and I haven't said anything in over a week? Show the last 5 by staleness, with the customer's last message quoted.
This is exactly get_featurebase_stalled_promises({ minDaysSinceAdminReply: 7 }).
Detect duplicates
Search the board for "export to CSV" and "download as spreadsheet". Cluster the matches by similarity and tell me which ones look like duplicates I should merge.
This uses search_featurebase_posts for both queries and then a similarity grouping.
Create a GitHub issue from a feature request
Take post
more-byok-options, summarize it as a single-paragraph problem statement, and produce a GitHub-issue-formatted markdown block (title + body) that I can paste into our repo.
The agent reads the post body, formats it, and you paste the result into GitHub.
Voice-of-customer report
Read the 20 most-recent open posts. Group them by theme. For each theme, give me: how many users mentioned it, the total upvotes, and one representative quote.
This uses list_featurebase_posts(status="open", sortBy="date:desc", limit=20) plus per-post comment reads.
Find unanswered posts
List all open posts with the
in_progressstatus that have zero admin replies. These are the ones we should respond to first.
This is list_featurebase_posts(hasAdminReply=false, status="in_progress").
Discover your team IDs
Find my user ID on this board. My name is "Krishna".
This uses find_featurebase_user({ name: "Krishna" }). Use the returned IDs as teamUserIds in subsequent calls — no env-var setup needed.
Tools
Seven read-only tools. Each one is designed to be cheap enough to chain — most listing calls don't fetch comments at all unless you ask for engagement.
list_featurebase_posts
Args:
status— one of the friendly names below; the server maps them to the underlyingpostStatus.typevalues returned by the public board:Friendly name
postStatus.typeopenopenin_reviewreviewingplannedunstartedin_progressactivecompletedcompletedThe default
allskips the filter and returns every status.sortBy—date:desc(default),date:asc, orupvotes:desc.limit— 1–200, default 50.hasAdminReply— optional boolean. Requires a team identity (env var orteamUserIdsoverride). If neither is set, the call throwsInvalidParams.teamUserIds— optional string[] override for the team.
Returns: { totalResults, availableResults, truncated, returned, posts: NormalizedPost[] }
Behavior:
A normal listing call (no
hasAdminReply) does not fetch comments and does not populate engagement metadata. It returns posts withauthor.role === "unknown"when no team is configured.When
hasAdminReplyis provided, comments are fetched for posts withcommentCount > 0and engagement is computed under the team. Posts withcommentCount === 0are treated ashasAdminReply: false(the team definitively has not replied) without a comment API request.
get_featurebase_post
Args:
slug— required (e.g.more-byok-options).include_comments— defaultfalse. Whentrue, inlines the full comment thread ascomments: NormalizedComment[].teamUserIds— optional string[] override.
Returns: { ...NormalizedPost, contentHtml, contentText, comments?, commentsError? }
contentHtml and contentText are always inlined. If the comments fetch fails, commentsError is set and the post is still returned.
When teamUserIds is supplied, both comment-author roles and engagement fields are reclassified against that team. A non-empty teamUserIds array replaces FEATUREBASE_TEAM_USER_IDS for that call only; an empty array [] is treated as absent (the env var is used if configured).
get_featurebase_posts (batch)
Args: slugs (1–20), include_content (default false).
Returns posts in the order requested; missing slugs go into notFound rather than throwing. Set include_content=true to inline full body on each entry.
search_featurebase_posts
Args: query (required), limit (1–50, default 10).
Returns posts ordered by relevance (title hit = 3 pts, body hit = 1 pt, per-token matches also weighted).
get_featurebase_stats
Args: topVotedLimit (1–50, default 5), recentLimit (1–50, default 5).
Returns: { totalResults, snapshotSize, truncated, snapshotWindow, statusCountsInSnapshot, categoryCountsInSnapshot, topVoted[N], recent[N] }
snapshotWindow is the actual date range currently in the in-memory snapshot — labels like *InSnapshot are explicit that these counts are over the snapshot, not over a complete board snapshot from a single source. The snapshot is built on demand from the public listing endpoint and is fresh as of the first fetch in the current process.
get_featurebase_stalled_promises
Args:
minDaysSinceAdminReply— 0–365, default 7.limit— 1–50, default 20.teamUserIds— optional string[] override.status— restrict candidates to one of these statuses.sortBy—staleness(default),freshness, orupvotes.
Returns: { minDaysSinceAdminReply, teamSource, warning?, unusedTeamUserIds?, unusedTeamUserIdsComplete?, totalCandidates, returned, promises: StalledPromise[] }
teamSource is "override" (per-call team), "default" (env-var team), or "none" (no team — returns empty with a warning).
unusedTeamUserIds lists IDs you supplied that didn't appear in any comment thread. unusedTeamUserIdsComplete: false signals that some comment fetches failed and we couldn't fully determine unused IDs.
find_featurebase_user
Args: name (≥2 chars, partial match), sampleSize (0–20, default 5).
Returns: { query, samplePostsScanned, commentsComplete, warning?, matches: UserMatch[] }
commentsComplete is true only when every comment fetch for the index build succeeded; false means totals may undercount.
Each UserMatch carries userId, name, postCount, commentCountInSampledPosts, totalCommentCount (board-wide), and guessedRole.
Known limitations
Reads only. Posting comments, voting, changing status all require authenticated access to Featurebase — out of scope.
Designed for public boards. Works on Remalt and on other public boards that expose the same public listing + comment endpoints. Boards with aggressive bot protection, sign-in walls, or non-standard layouts may not work.
No real-time updates. The in-memory snapshot is fresh on first fetch in a given process and cached for 5 minutes. Restart the server to flush.
Admin role tagging requires team IDs. Without
FEATUREBASE_TEAM_USER_IDS(or a per-callteamUserIds), author roles are"unknown"andhasAdminReplyfiltering is refused.
How it works (briefly)
The public board exposes
/api/v1/submission?…&page=N(the SPA's axiosbaseURLis/api). The server calls page 1 to learntotalPagesandtotalResults, then fetches pages 2..N concurrently. Listing pagination is atomic — if any required page fails, the entire tool call surfaces the failure and no partial listing is cached or returned./api/v1/comment?submissionId=<id>&page=Nreturns the comment thread. Comment pagination is also atomic — a single failed page throws and is never cached as a partial thread.Engagement fields (
hasAdminReply, counts, dates) are computed from the classified comment tree. The cache is role-neutral: roles are derived per request against the active team set, never stored on the cached tree.
Troubleshooting
Listing fails with Incomplete listing: failed pages N of M
The listing endpoint returned an error on one or more pages. The tool call surfaces this failure — no partial listing is returned or cached. Retry on the same client will refetch every listing page from scratch. This is by design (atomic contract).
engagementComplete: false in a list_featurebase_posts(hasAdminReply=…) response
Means one or more specific comment-thread fetches failed during engagement enrichment. The response includes failedPostSlugs listing which posts couldn't be classified. Posts that did succeed are still filtered correctly; only the affected posts get commentFetchFailed: true and are excluded from the filter result. Retry the request after a short delay.
commentsComplete: false in find_featurebase_user
At least one post's comments failed to fetch while building the board-wide user-count index. totalCommentCount for users who only appeared in failed threads may undercount. Retry after a short delay.
All author roles show "unknown"
No team is configured. Either set FEATUREBASE_TEAM_USER_IDS in the env, or use find_featurebase_user to discover IDs and pass them as teamUserIds per-call.
hasAdminReply filter throws InvalidParams
You asked for a team-based filter without providing a team. Set FEATUREBASE_TEAM_USER_IDS or pass teamUserIds to the call.
commentsError is set on a get_featurebase_post response
The post is still returned with its body and metadata; only the comments array is missing. Common causes: network error, rate limit, or the comment endpoint returning an unexpected shape.
For contributors
If you want to develop on this:
git clone https://github.com/K-Jadeja/open-featurebase-mcp
cd open-featurebase-mcp
npm ci
npm run build
npm test # 339 deterministic checks; no live network
npm start # launches the stdio serverThe default npm test is fully offline (mock fetcher fixtures). A separate npm run test:live runs against a live Featurebase endpoint and is opt-in.
License
MIT
This server cannot be installed
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/K-Jadeja/open-featurebase-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server