Key featuresFeaturesPricingSecurityDocsChangelog
Log inStart for free

Getting Started

  • What is QA Note?
  • Quick Start Guide
  • Install Extension
  • Project Members

Feature Guide

  • Screenshot & Annotation
  • Session Recording
  • Maintenance Reports
  • Issue State Model
  • Multi-issue Windows
  • Storage · DOM Snapshot

Integrations

  • GitHub
  • Commit Keys
  • MCP Server
  • Slack
  • Webhook
  • Vercel
  • Existing Playwright

API Reference

  • Authentication
  • Endpoint Reference
  • Public API v1
  • Error Handling

The issue tracker you use with your AI agent. Your agent fixes; QA Note keeps the record.

Made in Seoul · © 2026 QA Note
ProductKey featuresFeaturesPricingSecurityChangelog
ResourcesDocsMCP guideChrome Extension
CompanyBrandTerms of ServicePrivacy Policy

ffgg|CEO: Songwook Han

Business Registration No.: 746-54-00870[Verify]|E-Commerce License No.: 2024-Seoul Mapo-2178

Address: 5F, 26 World Cup buk-ro 6-gil, Mapo-gu, Seoul, Republic of Korea

Email: support@qanote.app|Hosting Provider: Vercel Inc.

© 2026 QA Note. All rights reserved.

Terms of ServicePrivacy PolicyCookie Policy
  1. Home
  2. /
  3. Docs
  4. /
  5. Integrations

MCP Server

Connect AI coding tools like Claude Code and Cursor to QA Note with a single OAuth click — query and manage issues directly

Table of Contents
  • What is MCP?
  • One-click install
  • Auth methods at a glance
  • Method A. Remote HTTP + one-click OAuth (recommended)
  • Claude Code
  • Cursor
  • Codex (OpenAI)
  • OAuth flow under the hood
  • Method B. Local binary (stdio · npx)
  • Claude Code
  • Cursor / Codex
  • Authentication flow
  • Method C. API Key (CI · headless · fallback)
  • API Key with Remote HTTP
  • API Key with stdio binary
  • Environment variables (stdio binary)
  • Available tools
  • Query tools
  • Write tools
  • Project list lookup
  • When to use it
  • Input
  • Response fields
  • Permissions and multi-org behavior
  • LLM usage scenarios
  • Recommended workflows
  • Verify setup
  • Troubleshooting
  • OAuth browser window does not open (Remote HTTP)
  • "Unauthorized" error
  • invalid_grant — Refresh token reuse detected
  • MCP server won't connect (stdio binary)
  • Reset token/session
  • SSH · Docker — no browser available

What is MCP?

MCP (Model Context Protocol) is a standard protocol that lets AI coding tools access external data. Connecting the QA Note MCP server is the handoff path: your agent in Claude Code, Cursor, or Codex receives the issue, works on the fix, and writes progress back to QA Note automatically — so the record keeps itself while developers stay in their own tools.

QA Note delivers rich technical metadata (console logs, network requests, JS errors, performance metrics, React component trees, user actions, element styles, DOM snapshots) to the agent in structured form — a work order it can act on immediately. Note the boundary: agents can record up to fix submitted; transitioning to verified or closed is reserved for humans and report publishing.

One-click install

Pick the MCP client you use and the copy or deep-link action runs immediately. The first connection opens a single browser OAuth consent window.

Pick your MCP client

Each card triggers a copy or deep-link install. The first connection opens a one-time browser OAuth consent.

>_

Claude Code

One CLI line · OAuth one-click

claude mcp add --transport http qanote https://beta.qanote.app/api/mcp

Paste into your terminal — the browser sign-in + consent window opens automatically.

Official install docs

Codex

Shared CLI/IDE config.toml · OAuth login

codex mcp add qanote --url https://beta.qanote.app/api/mcp codex mcp login qanote

Run it in your terminal to register the server, then complete OAuth in the browser. The IDE extension uses the same config.

Official install docs

Claude Desktop

Copy the mcpServers config JSON

{ "mcpServers": { "qanote": { "type": "http", "url": "https://beta.qanote.app/api/mcp" } } }

Config file: macOS ~/Library/Application Support/Claude/claude_desktop_config.json · Windows %APPDATA%\Claude\claude_desktop_config.json

Official install docs

Cursor

One-click deep link into Cursor

cursor://anysphere.cursor-deeplink/mcp/install?name=qanote&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vYmV0YS5xYW5vdGUuYXBwL2FwaS9tY3AifQ

Not using Cursor? Paste the config JSON into ~/.cursor/mcp.json instead.

Official install docs

Windsurf

Copy the mcpServers config JSON (serverUrl key)

{ "mcpServers": { "qanote": { "type": "http", "serverUrl": "https://beta.qanote.app/api/mcp" } } }

Paste into Windsurf → Cascade → MCP Servers → Add Server.

Official install docs

ChatGPT

Developer Mode connector URL

https://beta.qanote.app/api/mcp

ChatGPT → Settings → Connectors → enable Developer Mode → Add MCP server.

Official install docs

Auth methods at a glance

MethodWhen to useKey requiredRecommendation
Remote HTTP + OAuthEveryday desktop use (Claude Code, Cursor, Codex)No (one-time browser consent)★★★ Default
stdio local binaryCorporate proxy blocks HTTP MCP · offline credential cacheNo (same OAuth)★★
API KeyCI/CD · headless servers · MCP clients without OAuthYes, manual qn_... from dashboard★ (fallback)

The default path is one-click OAuth — no need to paste an Authorization header. Claude Code discovers the QA Note authorization server through the standard MCP discovery endpoint (/.well-known/oauth-protected-resource) and performs Dynamic Client Registration (RFC 7591) → Authorization Code + PKCE S256 → access/refresh token exchange automatically.

Method A. Remote HTTP + one-click OAuth (recommended)

Connect directly to the hosted MCP endpoint at https://qanote.app/api/mcp. No binary install, no API key copy-paste.

Claude Code

One line in your terminal:

bash
claude mcp add --transport http qanote https://qanote.app/api/mcp

After registering, run /mcp in Claude Code — your browser opens automatically, and a single QA Note sign-in + consent completes authentication. The resulting access/refresh tokens are stored safely inside Claude Code and refreshed transparently from then on.

Cursor

Add to ~/.cursor/mcp.json:

json
{
  "mcpServers": {
    "qanote": {
      "url": "https://qanote.app/api/mcp"
    }
  }
}

No headers — Cursor launches the OAuth browser window on first tool call.

Codex (OpenAI)

Same entry under mcpServers in your Codex CLI config:

json
{
  "mcpServers": {
    "qanote": {
      "url": "https://qanote.app/api/mcp"
    }
  }
}

OAuth flow under the hood

  1. The client calls https://qanote.app/api/mcp → 401 Unauthorized with WWW-Authenticate: Bearer resource_metadata=...
  2. The client reads /.well-known/oauth-protected-resource (RFC 9728) → /.well-known/oauth-authorization-server (RFC 8414) to get the authorization server metadata
  3. Dynamic Client Registration (RFC 7591) issues a client_id automatically (no user action needed)
  4. Authorization Code + PKCE S256 flow — browser sign-in + MCP consent
  5. /api/oauth/token returns an access token (scopes mcp + offline_access, bound with aud=https://qanote.app/api/mcp — RFC 8707) and a refresh token
  6. Subsequent requests keep the same refresh token and silently renew only the access token

The "MCP Prompt" button on each issue page copies a prompt that embeds the issue permalink so the LLM can pull the full context with a single resolve_by_url call.

Method B. Local binary (stdio · npx)

Use this when your corporate network blocks HTTP MCP, or when you want credentials cached locally for offline/SSH environments. The auth itself is the same OAuth browser flow.

Claude Code

bash
claude mcp add qanote -- npx -y @qanote/mcp-server

Cursor / Codex

json
{
  "mcpServers": {
    "qanote": {
      "command": "npx",
      "args": ["-y", "@qanote/mcp-server"]
    }
  }
}

Authentication flow

  1. On first launch, if no stored credential exists, the browser opens automatically
  2. Log in with your QA Note account (if already signed in, only the consent step remains)
  3. The resulting token is saved to ~/.qanote/credentials.json with chmod 600
  4. Subsequent runs reuse the stored token automatically and silently renew only the access token

To reset credentials:

bash
rm ~/.qanote/credentials.json

Method C. API Key (CI · headless · fallback)

Use this only in environments where a browser cannot be opened (CI/CD, containers, remote servers) or with MCP clients that do not support OAuth.

  1. QA Note Dashboard → Organization Settings → API Keys
  2. "New API Key" → enter a name (e.g., QA Note production server), pick an expiry and permissions → "Create"
  3. Copy the displayed key (qn_...) immediately to a safe location (shown only once)

For server-side data import, keep the default projects:read + issues:read permissions. Add issues:write only when the automation needs to update issue status or create comments. To keep production and developer credentials separate, use an API Key for the server and a separate OAuth connection for interactive tools like Claude Code.

API Key with Remote HTTP

bash
claude mcp add --transport http qanote https://qanote.app/api/mcp \
  --header "Authorization: Bearer qn_YOUR_KEY"

Cursor / Codex JSON:

json
{
  "mcpServers": {
    "qanote": {
      "url": "https://qanote.app/api/mcp",
      "headers": { "Authorization": "Bearer qn_YOUR_KEY" }
    }
  }
}

API Key with stdio binary

json
{
  "mcpServers": {
    "qanote": {
      "command": "npx",
      "args": ["-y", "@qanote/mcp-server"],
      "env": {
        "QANOTE_API_KEY": "qn_YOUR_KEY"
      }
    }
  }
}

Environment variables (stdio binary)

VariableRequiredDescriptionDefault
QANOTE_API_KEYOptionalAPI Key (qn_...). Uses OAuth browser login if not set—
QANOTE_URLOptionalQA Note server URLhttps://qanote.app

Remote HTTP does not need environment variables since the client specifies the url directly.

Available tools

Query tools

ToolDescription
resolve_by_urlLoad an issue + tech context in one call from a permalink or short link (/i/<code>-<number>) (recommended entry point)
list_projectsList accessible projects
search_issuesSearch and filter issues (status · priority · labels · query)
list_issue_queueSequential work queue for terminal LLM workflows
get_issueIssue detail + metadata summary
list_commentsList comments on an issue
get_commentsList comments on an issue (list_comments alias)
get_console_logsBrowser console logs (errors/warnings sorted first)
get_network_logsNetwork request logs (errors only by default, full list available)
get_user_actionsPre-issue user actions converted to natural language
get_tech_contextCombined JS errors · performance · React tree · environment info
get_element_stylesComputed style · box model · parent/sibling gap
get_performance_metricsWeb Vitals · Navigation Timing
get_environment_infoBrowser · OS · network · GPU · fonts, etc.
get_js_errorsRuntime errors + stack trace
get_react_component_treeReact component tree snapshot
get_storagelocalStorage · sessionStorage · cookies (masked)
get_dom_snapshotDOM outerHTML (scripts and input values masked)
get_screenshotsScreenshot URLs + embedded image content

Write tools

ToolDescription
claim_issueMark work as started: move the issue to in_progress and add a start comment
complete_issueRecord completion: add PR/deployment/validation details and move to resolved or closed
update_issueChange issue status/priority
add_commentAdd a comment to an issue

Project list lookup

list_projects is the first discovery tool an LLM should use when the user has not provided an issue URL.

When to use it

  • "Show me the QA Note project list"
  • "Show only projects in the studiobaton organization"
  • "Find critical issues in the qa-note project"
  • "Show the next issue queue from a project I can access"

If the user already pasted an issue permalink, call resolve_by_url first instead.

Input

ParameterRequiredDescription
organization_slugOptionalReturn only projects in one organization. Example: studiobaton

Response fields

list_projects returns a JSON array.

FieldDescription
idProject ID to pass to search_issues, get_issue, list_issue_queue, etc.
nameProject display name
slugProject slug used in dashboard URLs
createdAtProject creation timestamp
organizationIdOrganization ID
organizationSlugOrganization slug, used to disambiguate multi-org accounts
organizationNameOrganization display name

Example:

json
[
  {
    "id": "018f2f4b-...",
    "name": "QA Note",
    "slug": "qa-note",
    "description": null,
    "createdAt": "2026-04-21T08:13:44.000Z",
    "organizationId": "018f2d10-...",
    "organizationSlug": "studiobaton",
    "organizationName": "Studio Baton"
  }
]

Permissions and multi-org behavior

  • OAuth connections are user-scoped. If the user belongs to multiple organizations, projects from every accessible active organization are returned.
  • API Key connections return projects only from the organization that issued the key.
  • Different organizations can have projects with the same slug. The LLM should resolve projects by organizationSlug + slug or by id, not by slug alone.
  • If the organization is ambiguous, the LLM should ask the user which organization to use instead of picking the first result.

LLM usage scenarios

User: "Show me the QA Note project list"
LLM: Call list_projects({}) → summarize organization name/slug and project name/slug
User: "Show open issues in the QA Note project under studiobaton"
LLM:
1. list_projects({ "organization_slug": "studiobaton" })
2. Select the project whose slug or name matches QA Note
3. search_issues({ "project_id": "<id>", "status": "open" })
User: "Find critical issues in the qa-note project"
LLM:
1. list_projects({})
2. If multiple projects have slug qa-note, ask "Which organization: studiobaton/qa-note or client-a/qa-note?"
3. Call search_issues with the confirmed project_id
User: "Show my next work queue for qa-note"
LLM:
1. list_projects({})
2. Resolve the project by organizationSlug + slug
3. list_issue_queue({ "project_id": "<id>", "status": "open", "sort": "board_order" })

Recommended workflows

Just make natural-language requests to your AI coding tool:

# Search issues
"Find critical issues in QA Note"

# Debugging context
"Show me the console errors and network logs for issue #42"

# Reproduce user behavior
"Tell me what the user did in issue #15"

# Update an issue
"Move issue #42 to resolved and leave a comment about the fix"

Optimal debugging sequence:

  1. Copy a permalink-embedded prompt from the "MCP Prompt" button on any issue page → one resolve_by_url call
  2. Dig deeper with get_tech_context · get_console_logs · get_network_logs
  3. After resolution, call update_issue to change status and add_comment to record cause/fix

Verify setup

After setup, try asking your AI tool:

Show me the project list from QA Note

If the project list appears, setup is complete.

Troubleshooting

OAuth browser window does not open (Remote HTTP)

  • In firewall/popup-blocker environments, copy the authorize URL printed by Claude Code into a browser manually to finish sign-in + consent. The token is then saved automatically.
  • If a corporate proxy blocks .well-known/oauth-* discovery, switch to Method B (stdio binary) or use Method C (API Key).

"Unauthorized" error

  • OAuth path: the stored token has expired or was revoked. Restart the MCP server to re-trigger browser login. For the stdio binary, delete ~/.qanote/credentials.json.
  • API Key path: verify the key starts with qn_ and has not been revoked. To access a different organization's resources, issue a new key in that organization.

invalid_grant — Refresh token reuse detected

This can appear during migration from the older OAuth server behavior that rotated MCP refresh tokens. The current server keeps MCP refresh tokens persistent, so repeated refreshes with the same token should work. If the error persists, delete the client's stored OAuth token once and reconnect.

MCP server won't connect (stdio binary)

  • Run npx -y @qanote/mcp-server directly in your terminal to confirm it boots
  • Requires Node.js 20+
  • Check that QANOTE_URL / QANOTE_API_KEY are set correctly in the MCP config's env block

Reset token/session

bash
# stdio binary
rm ~/.qanote/credentials.json

# Remote HTTP (Claude Code)
claude mcp remove qanote
claude mcp add --transport http qanote https://qanote.app/api/mcp

SSH · Docker — no browser available

→ Use Method C (API Key). Injecting the key via environment variable or --header is the safest option for CI/CD pipelines.

Previous
Commit Keys
Next
Slack

Table of Contents

  • What is MCP?
  • One-click install
  • Auth methods at a glance
  • Method A. Remote HTTP + one-click OAuth (recommended)
  • Claude Code
  • Cursor
  • Codex (OpenAI)
  • OAuth flow under the hood
  • Method B. Local binary (stdio · npx)
  • Claude Code
  • Cursor / Codex
  • Authentication flow
  • Method C. API Key (CI · headless · fallback)
  • API Key with Remote HTTP
  • API Key with stdio binary
  • Environment variables (stdio binary)
  • Available tools
  • Query tools
  • Write tools
  • Project list lookup
  • When to use it
  • Input
  • Response fields
  • Permissions and multi-org behavior
  • LLM usage scenarios
  • Recommended workflows
  • Verify setup
  • Troubleshooting
  • OAuth browser window does not open (Remote HTTP)
  • "Unauthorized" error
  • invalid_grant — Refresh token reuse detected
  • MCP server won't connect (stdio binary)
  • Reset token/session
  • SSH · Docker — no browser available