FrancoLabs MCP Server
README.md
# FrancoLabs MCP Server
Connect AI assistants to [FrancoLabs](https://francolabs.vercel.app) — a UX
research platform — over the [Model Context Protocol](https://modelcontextprotocol.io).
Let Claude, ChatGPT and other MCP clients create and manage studies, browse
templates, read participant responses and analytics, run AI-grounded analysis,
and turn insights into product opportunities on your behalf.
- **Endpoint:** `https://francolabs.vercel.app/mcp`
- **Transport:** Streamable HTTP (MCP protocol `2025-06-18`)
- **Auth:** OAuth 2.1 (Dynamic Client Registration + PKCE) or Personal Access Token
- **Registry:** `io.github.glauberfrancodesign/francolabs`
---
## Connect
### Claude (claude.ai / Desktop)
Settings → **Connectors** → *Add custom connector* → URL:
```
https://francolabs.vercel.app/mcp
```
Complete the OAuth consent screen — you choose exactly which scopes to grant and
can toggle read-only access.
### ChatGPT
Enable **Developer Mode**, then Settings → **Connectors** → *Add* → same URL.
Authenticate via the OAuth flow.
### Claude Code / Cursor (manual token)
Generate a Personal Access Token in
[Settings → Integrations](https://francolabs.vercel.app/settings/integrations), then:
```bash
claude mcp add --transport http francolabs \
"https://francolabs.vercel.app/mcp" \
--header "Authorization: Bearer <your-token>"
```
---
## Tools
A tool listed with two scopes needs both. **AI** marks tools that call a language
model and use AI credits; the model only sees the deterministic digest and curated
insights, with e-mail addresses and phone numbers masked first.
### Templates, workspaces and projects
| Tool | Scope | Description |
|------|-------|-------------|
| `list_question_types` | `templates:read` | Question/block types with the exact settings shape and a valid example |
| `list_templates` | `templates:read` | Study templates, optionally by category |
| `list_workspaces` | `projects:read` | Workspaces (teams) you belong to and your role in each |
| `list_projects` | `projects:read` | Your projects, optionally by status |
| `get_project` | `projects:read` | A single project by id |
| `get_plan` | `projects:read` | The workspace plan and current usage: limits, what is enforced now, grants and when extended access ends, and the per-person AI-create cap |
| `create_project` | `projects:write` | Create a project (optionally in a specific workspace) |
### Studies
| Tool | Scope | Description |
|------|-------|-------------|
| `list_studies` | `studies:read` | Studies, filtered by status and/or project |
| `get_study` | `studies:read` | A full study with blocks and settings |
| `create_study` | `studies:write` | Create a Draft study; blocks are validated against `list_question_types` |
| `update_study` | `studies:write` | Update title, blocks, project; `settings` is a partial update |
| `set_study_status` | `studies:write` | Launch a Draft, pause, resume a Paused study, or complete it |
| `delete_study` | `studies:write` | Permanently delete a study and its responses |
| `generate_study_from_objective` | `studies:read` | **AI** — turn a research objective into a typed study skeleton |
| `review_study_quality` | `studies:read` | **AI** — survey-design review with a quality score per block |
### Responses, analysis and insights
| Tool | Scope | Description |
|------|-------|-------------|
| `list_responses` | `responses:read` | Raw participant responses, newest first — **may contain personal data** written by respondents; pass `redact: true` to mask e-mails and phones |
| `get_study_analytics` | `responses:read` | Aggregated KPIs: responses, completion, duration, NPS, distributions |
| `get_study_digest` | `responses:read` | Deterministic, PII-free statistical digest for every question type |
| `run_universal_analysis` | `responses:read` + `studies:write` | **AI** — run/refresh the full analysis (replaces non-pinned AI insights) |
| `analysis_chat` | `responses:read` | **AI** — ask a question grounded in the digest and cached analysis |
| `get_insights` | `responses:read` | Curated insight cards, pinned first |
| `upsert_insight` | `responses:read` + `studies:write` | Create or edit a curated insight card |
| `rate_insight` | `responses:read` + `studies:write` | Record 👍/👎 feedback on an insight |
| `suggest_tags` | `responses:read` + `studies:write` | **AI** — tag insights with a consistent product taxonomy |
| `set_insight_tags` | `responses:read` + `studies:write` | Replace the tags of one insight |
| `research_memory_query` | `responses:read` + `studies:write` | **AI** — cross-study question answered from past curated insights |
### Opportunities and decisions
| Tool | Scope | Description |
|------|-------|-------------|
| `list_opportunities` | `responses:read` | Product opportunities distilled for a study |
| `create_opportunity_from_insights` | `responses:read` + `studies:write` | **AI** — distill insights into draft opportunities |
| `suggest_next_research_steps` | `responses:read` | **AI** — 3–5 follow-up studies that de-risk open opportunities |
| `generate_decision_packet` | `responses:read` + `studies:write` | **AI** — stakeholder-ready decision package (Markdown) |
| `list_decision_packets` | `responses:read` | Decision packages already generated for a study |
| `export_opportunity` | `responses:read` + `studies:write` | Export an opportunity to Linear as an issue — internal users only |
| `list_external_task_links` | `responses:read` | Linear issues already created from a study's opportunities |
### Contacts (personal data)
| Tool | Scope | Description |
|------|-------|-------------|
| `list_contacts` | `contacts:read` | Respondent contacts of the workspace — **personal data** (e-mail, name, locale/country, research consent, tags, response counts) |
| `get_contact` | `contacts:read` | One contact with the studies they answered — **personal data** |
| `tag_contacts` | `contacts:write` | Add/remove tags on contacts to segment respondents — never put sensitive information in tags |
`create_project` and `create_study` write into a workspace — pass `workspaceId`
(see `list_workspaces`), or omit it to use your oldest workspace by default.
Write tools also require an editor role (owner, admin or member) in the study's
workspace; viewers can only read.
Two resources are also exposed: `francolabs://templates` and
`francolabs://question-types`.
## Scopes
`templates:read` · `projects:read` · `projects:write` · `studies:read` ·
`studies:write` · `responses:read` · `contacts:read` · `contacts:write`
**`contacts:read` and `contacts:write` give access to personal data** of your
respondents (e-mail, name, locale/country, research consent, tags and response
history). They are opt-in: the consent screen and the **Read-only** token preset
leave them unchecked; grant them only to assistants that need your contacts base.
`responses:read` returns raw answers, which can also contain personal data typed by
respondents.
Tools you didn't grant are hidden from `tools/list`. A **read-only** grant blocks
every write tool server-side, regardless of scopes.
## Security
- Tokens are stored only as SHA-256 hashes — never in plaintext.
- Each request mints a short-lived (5 min) JWT so all data access runs under
per-user row-level security; the service role is used only for the token lookup.
- OAuth access and refresh tokens last 30 days; a connection never outlives
90 days. Access is revocable anytime from Settings → Integrations, and clients
can revoke a token at the revocation endpoint (RFC 7009).
- OAuth follows RFC 9728 (protected-resource discovery), RFC 8414 (AS metadata),
RFC 7591 (dynamic client registration) and PKCE S256.
## Source
This repository mirrors the server's source for transparency. The server runs as
a Supabase Edge Function (`src/mcp`, `src/mcp-oauth`, `src/_shared`).
---
© FrancoLabs. All rights reserved.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues