Notra README

The full upstream README, mirrored for reference. Install config, tool schemas, adoption signals and our own overview live on the Notra listing page.

Notra MCP Server

An MCP (Model Context Protocol) server for the Notra API. It manages posts, brand identities, integrations, schedules, GEO visibility scans, competitors, content briefs, and AI traffic analytics.

Setup

You can generate an API key from your Notra workspace dashboard under Developer > API Keys.

Node.js 20 or newer is required.

Claude Desktop

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

config.json
{
  "mcpServers": {
    "notra": {
      "command": "npx",
      "args": ["-y", "@usenotra/mcp"],
      "env": {
        "NOTRA_API_KEY": "your-api-key"
      }
    }
  }
}

Claude Code

Terminal
claude mcp add notra -- npx -y @usenotra/mcp

Then set the NOTRA_API_KEY environment variable in your shell before launching Claude Code.

Codex

server.ts
export NOTRA_API_KEY=your-api-key
codex mcp add notra --env NOTRA_API_KEY="$NOTRA_API_KEY" -- npx -y @usenotra/mcp

Run codex mcp list to verify the connection. The Codex CLI, desktop app, and IDE extension share this MCP configuration.

OpenCode

Set NOTRA_API_KEY in your shell, then add the server to your project-level opencode.json or the global ~/.config/opencode/opencode.json:

config.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "notra": {
      "type": "local",
      "command": ["npx", "-y", "@usenotra/mcp"],
      "enabled": true,
      "environment": {
        "NOTRA_API_KEY": "{env:NOTRA_API_KEY}"
      }
    }
  }
}

Amp

Run amp config edit and add the following to your settings, or place it in .amp/settings.json for a workspace-specific configuration:

config.json
{
  "amp.mcpServers": {
    "notra": {
      "command": "npx",
      "args": ["-y", "@usenotra/mcp"],
      "env": {
        "NOTRA_API_KEY": "${NOTRA_API_KEY}"
      }
    }
  }
}

Set NOTRA_API_KEY in the environment before launching Amp. Workspace MCP servers may require approval with amp mcp approve notra.

Account API keys

An account API key belongs to you rather than one workspace, so it works in every workspace you're a member of. If you belong to more than one, choose the workspace this server acts on with NOTRA_ORGANIZATION_ID:

config.json
{
  "env": {
    "NOTRA_API_KEY": "your-account-api-key",
    "NOTRA_ORGANIZATION_ID": "your-workspace-id"
  }
}

Without it, tools fail with a message asking you to pick a workspace. list_workspaces works without a selection and shows the ids. Organization API keys ignore NOTRA_ORGANIZATION_ID.

Remote MCP (OAuth)

The hosted streamable HTTP server at https://mcp.usenotra.com/mcp uses OAuth as the primary authentication method. It supports the current 2026-07-28 MCP protocol as well as legacy 2025 clients. MCP clients should discover protected resource metadata at:

text
https://mcp.usenotra.com/.well-known/oauth-protected-resource

That metadata points to the Notra authorization server (WorkOS AuthKit) at https://oauth.usenotra.com, which supports dynamic client registration (RFC 7591). The MCP server also mirrors the authorization server metadata at https://mcp.usenotra.com/.well-known/oauth-authorization-server.

Workspace-scoped URL

Add a workspace id or slug to the URL to pin a connection to one workspace: https://mcp.usenotra.com/mcp/<workspace>. This is the way to pick a workspace in clients that only accept a URL and can't send custom headers.

  • Claude: Settings > Connectors > Add custom connector, URL https://mcp.usenotra.com/mcp/acme

  • Claude Code: claude mcp add --transport http notra https://mcp.usenotra.com/mcp/acme

  • Cursor (~/.cursor/mcp.json):

    config.json
    {
      "mcpServers": {
        "notra": { "url": "https://mcp.usenotra.com/mcp/acme" }
      }
    }
    

On a scoped URL:

  • API keys act in that workspace. The URL wins over an X-Notra-Organization-Id header. An organization key only works on its own workspace's URL; any other workspace is rejected with HTTP 403 by the Notra API.
  • OAuth works the same as on /mcp, but the workspace you authorize must be the one in the URL. Otherwise requests are rejected with HTTP 403 instead of silently acting on another workspace. The OAuth challenge announces the same resource as /mcp, so clients get a normal Notra token; the workspace in the URL is enforced through the workspace you authorize.
  • list_workspaces is hidden, since the connection can't switch workspaces. whoami still shows the current one.
  • Legacy 2025 sessions belong to the URL they were opened on; using the session id on another URL returns HTTP 401.

API key alternative

Remote connections also accept a Notra API key as a static Authorization: Bearer … header. Generate one from your Notra workspace dashboard under Developer > API Keys. OAuth-capable clients should prefer the OAuth flow instead of manual key configuration.

With an account API key that can reach several workspaces, use a workspace-scoped URL or add an X-Notra-Organization-Id: <workspace-id-or-slug> header (X-Organization-Id also works). The server forwards it to the Notra API on every call. A legacy 2025 session stays bound to the workspace it was initialized with; a request on that session that names a different workspace is rejected with HTTP 401, so open a new session to switch. OAuth connections ignore the header because each token is bound to the workspace chosen at consent.

For self-hosted HTTP deployments, OAuth validation can be configured with:

bash
WORKOS_AUTHKIT_DOMAIN=oauth.usenotra.com
WORKOS_CLIENT_ID=client_xxx
NOTRA_MCP_RESOURCE=https://mcp.usenotra.com

The issuer is https://{WORKOS_AUTHKIT_DOMAIN} and must match the iss claim in tokens minted by AuthKit; a mismatch causes every bearer token to be rejected. Token signatures are verified against https://{WORKOS_AUTHKIT_DOMAIN}/oauth2/jwks.

When NODE_ENV=development, the default AuthKit domain is essential-berry-67-development-2.authkit.app; production defaults to oauth.usenotra.com. auth.usenotra.com is the WorkOS Authentication API domain and serves none of the OAuth endpoints, so it does not work here.

Legacy 2025 sessions expire after 30 minutes of inactivity. Each OAuth user or API key can hold NOTRA_MCP_MAX_SESSIONS_PER_PRINCIPAL sessions (default 50); beyond that, its own least recently used session closes. When the server holds NOTRA_MCP_MAX_SESSIONS sessions (default 1000), new sessions are rejected with HTTP 503 and Retry-After instead of closing other users' sessions.

Hosted usage statistics

The HTTP server reports MCP usage to Notra's MCP server analytics through @usenotra/geo/mcp. Every JSON-RPC request the server answers is recorded with its method, tool name, status (ok, tool_error or rpc_error), latency, response size, session ID, and the client and server names and versions. tools/list answers also record the advertised tools. ping is skipped. Local stdio servers do not emit usage events.

Set the Notra GEO token on the hosted deployment to enable tracking:

env
NOTRA_GEO_TOKEN=your-geo-token

Without a token, tracking is disabled. OAuth calls are attributed to the WorkOS user_id; API-key calls carry no user. Unknown tool names are recorded as unknown. Tool arguments and results are never sent. Delivery is batched, asynchronous and best-effort: a failed delivery logs a credential-free warning without failing the tool call.

Toolsets

All 138 tools are exposed by default, which costs roughly 23k tokens of agent context (about 12k for geo alone, 11k for content). To load only what you need, pick toolsets with NOTRA_MCP_TOOLSETS (stdio and HTTP) or the toolsets query parameter on the remote endpoint:

ToolsetTools
contentPosts, Sites, brand identities, integrations, schedules, event triggers, webhooks, skills, feedback inbox
geoProjects and every GEO tool

Workspace tools and submit_feedback are always available.

bash
NOTRA_MCP_TOOLSETS=content npx -y @usenotra/mcp
text
https://mcp.usenotra.com/mcp?toolsets=geo

Tools

Workspace

ToolDescription
whoamiShow the current workspace and authenticated account information
list_workspacesList accepted and pending workspaces available to the authenticated account

Each MCP connection operates in the workspace bound to its bearer token, or for account API keys the workspace selected with NOTRA_ORGANIZATION_ID or the X-Notra-Organization-Id header. To act in another workspace, authorize or configure a separate connection for that workspace; list_workspaces discovers access but does not switch workspaces.

Posts

ToolDescription
list_postsList post summaries with optional filters for sorting, pagination, status, content type, and brand identity
get_postGet a single post by ID
get_post_agent_reachAI crawler, citation and referral visits to a post's live page on its Notra Site
create_postCreate a post from your own title and markdown
update_postUpdate a post's title, markdown, status, or credited authors
delete_postDelete a post
generate_postQueue async post generation from GitHub activity, one pull request, or your own brief
get_post_generation_statusCheck the status of a post generation job
create_post_pull_requestOpen a draft GitHub pull request for a saved blog post or changelog
get_post_scheduleGet a post's publishing schedule and per-destination status
schedule_postSchedule an existing post for publishing in Notra and optionally GitHub, X, or LinkedIn
cancel_post_scheduleCancel pending publishing destinations; already-publishing destinations finish on their own

To turn a pull request into a post, call generate_post with pullRequest (owner, repo, number) and optionally a brief, poll get_post_generation_status for the postId, then call create_post_pull_request to open a draft pull request with the post. Calling it again updates that pull request. A brief also works on its own to say what a post from recent activity should cover.

Post publishing schedules are separate from the content-generation schedules below. schedule_post requires an ISO 8601 scheduledAt timestamp, accepts an optional IANA timeZone (default UTC), and supports at most two external destinations. GitHub destinations use repositoryId from list_integrations and an optional merge flag (default true); social destinations use a connected X or LinkedIn accountId. Omitting destinations schedules publishing in Notra only.

Sites

Notra Sites are hosted blogs and changelogs built from a GitHub repository. Settings, domains, rollbacks and deletion stay in the dashboard. These tools need the sites.read and sites.write scopes.

ToolDescription
list_sitesList Notra Sites with their URL, live state and blog mount
get_siteGet a Site's settings, live deployment, custom domains and open previews
list_site_deploymentsList production and preview builds with status, commit and compiler diagnostics
get_site_deploymentGet one deployment with its diagnostics and build log
deploy_siteBuild and publish the newest commit on the production branch
redeploy_site_deploymentRebuild the same commit, for example to retry a failed build
preview_post_on_siteBuild a private preview of a Site with a saved post added, without touching the repository
get_site_post_previewGet the status and URL of a post's preview
publish_post_to_siteOpen or update a pull request that adds a post to the Site's repository; it goes live once merged
list_site_authorsList a site's blog.json authors, unpublished changes included, with post usage
upsert_site_authorCreate or replace a site author, or rename one with previousId
delete_site_authorRemove a site author
import_site_authorsCopy Notra authors into a site's blog.json
set_site_author_pageSet the author page layout (inline or stacked)
publish_site_designPublish the site's unpublished blog.json changes and deploy it

publish_post_to_site always opens or updates a pull request, even when the repository publishes directly from the dashboard.

Author changes are saved to the site's blog.json as unpublished Design changes, the same draft the dashboard's Design tab shows, and go live with publish_site_design or the dashboard's Publish. Author ids are 1 to 40 lowercase letters, digits and dashes, and links must be https:// URLs. Renaming or deleting an author that is live or credited on posts needs force. publish_site_design refuses while other files on the site have unpublished changes. To credit a site author on a blog post, pass its site:<id> ref in update_post's authorIds.

Brand Identities

ToolDescription
list_brand_identitiesList all brand identities
get_brand_identityGet a single brand identity by ID
update_brand_identityUpdate brand identity settings
delete_brand_identityDelete a brand identity
list_brand_colorsList a brand identity's guideline colors
create_brand_colorAdd a brand color
update_brand_colorUpdate a brand color
delete_brand_colorDelete a brand color
generate_brand_identityQueue async brand identity generation from a website URL
get_brand_identity_generation_statusCheck the status of a brand identity generation job

Integrations

ToolDescription
list_integrationsList enabled GitHub and Linear integrations
create_github_integrationConnect a public GitHub repository
list_github_activityList merged PRs, commits or releases of a connected repository
delete_integrationDelete a GitHub or Linear integration

Schedules

ToolDescription
list_schedulesList scheduled content generation jobs
create_scheduleCreate a schedule from GitHub and/or Linear
update_scheduleChange only the fields you pass on a schedule
delete_scheduleDelete a scheduled content generation job
run_scheduleRun a schedule once now (uses AI credits)
list_schedule_runsList a schedule's recent runs and their posts

Event Triggers

ToolDescription
list_event_triggersList triggers that generate content from GitHub releases or pushes
get_event_triggerGet a single event trigger by ID
create_event_triggerCreate an event trigger
update_event_triggerReplace an event trigger's configuration
delete_event_triggerDelete an event trigger

Webhooks

ToolDescription
list_webhook_endpointsList HTTPS endpoints subscribed to Notra events
delete_webhook_endpointRemove a webhook subscription and cancel unsent deliveries
list_webhook_deliveriesList webhook deliveries, optionally filtered by status
get_webhook_deliveryGet a delivery's payload and attempt history
retry_webhook_deliveryRetry a failed webhook delivery

Skills

ToolDescription
list_skillsList reusable writing skills
get_skillGet a single skill by name
create_skillCreate a reusable writing skill
update_skillUpdate a reusable writing skill
delete_skillDelete a reusable writing skill

Projects

GEO features are scoped to a project. Most GEO tools take a projectId; call list_projects first to find it. GEO tools require an organization-scoped API key and the GEO plan.

ToolDescription
list_projectsList the organization's GEO projects
get_projectGet a single project by ID
create_projectCreate a project, optionally linked to a brand
update_projectRename a project or relink its brand identity
delete_projectDelete a project and all of its GEO data (cascading)

GEO settings

ToolDescription
get_geo_settingsGet tracked company, aliases, languages, engines and scan config
list_geo_enginesList the engine IDs a project can track
update_geo_settingsChange only the given settings and restart the scan cycle

GEO prompts and sequences

ToolDescription
list_geo_promptsList tracked prompts (custom and auto-derived)
create_geo_promptTrack a new prompt
update_geo_promptEnable or disable a tracked prompt
delete_geo_promptStop tracking a prompt
import_geo_promptsBulk import prompts from rows or CSV
list_geo_prompt_suggestionsList prompts suggested from Search Console queries
accept_geo_prompt_suggestionTrack a suggested prompt
dismiss_geo_prompt_suggestionDismiss a suggested prompt
list_geo_sequencesList multi-turn prompt sequences
create_geo_sequenceCreate a prompt sequence
update_geo_sequenceUpdate a sequence's name, steps or enabled state
delete_geo_sequenceDelete a sequence
run_geo_sequenceRun a sequence now; consumer apps queue a scan (uses AI credits)

GEO personas

ToolDescription
list_geo_personasList buyer personas with their profile, memories and conversation prompts
update_geo_personaTurn a persona on or off, or edit its details (clears its conversation prompts)
archive_geo_personaArchive a persona; its past results stay readable
restore_geo_personaRestore an archived persona, disabled
get_geo_persona_resultsGet one scan's persona conversation turns per engine
get_geo_persona_activityGet daily checks and mentions per persona
run_geo_personaPlay a persona's conversation now; consumer apps queue a scan (uses AI credits at 2x)
generate_geo_personasGenerate a full set, add one from a brief, or regenerate one (uses AI credits)
get_geo_persona_generation_statusCheck the latest persona generation job

GEO competitors

ToolDescription
list_geo_competitorsList tracked competitors
upsert_geo_competitorCreate, update or rename a competitor
suggest_geo_competitorsAI-discover likely competitors for a domain
delete_geo_competitorStop tracking a competitor
import_geo_competitorsBulk import competitors from rows or CSV

GEO scans and visibility

ToolDescription
create_geo_scanTrigger an async visibility scan (uses AI credits)
rescan_geo_promptScan a single prompt again (uses AI credits)
list_geo_scansList scans with pagination
get_geo_scanGet a scan and its status
get_geo_snapshotCompact cross-signal diagnosis and recommended next actions
get_geo_changesChanges between the two latest scans
get_geo_visibility_overviewMention rates per answer engine
get_geo_visibility_timeseriesDaily mention counts per engine
list_geo_prompt_result_summariesFiltered, paginated results without full answers or URLs
get_geo_prompt_result_detailFull answer and sources for one check
get_geo_prompt_historyCompact historical checks for one prompt
get_geo_sentimentSentiment metrics and previous-period comparison
get_geo_sentiment_analysisStored thematic sentiment analysis
list_geo_sentiment_evidencePaginated answers behind sentiment metrics
list_geo_shelf_sourcesPaginated citation shelf and opportunity state
get_geo_competitor_shareTop brands by share of voice, with brand filter and limit
get_geo_language_shareMention rates per tracked language
get_geo_competitor_detailOne competitor's mention history and the prompts driving it

GEO content briefs

ToolDescription
list_geo_content_gapsPrompts where competitors are mentioned and this brand is not
update_geo_content_gapIgnore a prompt gap or restore it
list_geo_content_briefsList content briefs and their statuses
plan_geo_content_briefResearch a topic and plan a brief (billed, can take minutes)
get_geo_content_briefGet a brief with the full document and writer status
update_geo_content_briefEdit a draft brief's outline and planning fields
approve_geo_content_briefApprove a brief and start the article writer

Agent readiness

ToolDescription
get_geo_agent_readinessLatest readiness report, score history and any scan in flight
start_geo_agent_readiness_scanQueue a readiness scan of the project's website

AI traffic

ToolDescription
get_geo_traffic_overviewCrawler and AI-referral totals, sources and daily timeseries
get_geo_traffic_logMost recent individual AI crawler/referral requests
list_geo_traffic_journeysSessions grouped by journey
get_geo_traffic_journeyEvery event in one journey
list_geo_traffic_pagesMost visited pages by AI traffic
get_geo_ingest_setupTracking install snippets and ingest endpoint

MCP server analytics

Usage of your own MCP server, reported by the @usenotra/geo SDK. Captured arguments, responses and end-user IDs stay in the dashboard.

ToolDescription
get_geo_mcp_analyticsCalls, errors, latency, clients, models, intents, recent failures and unused tools
get_geo_mcp_tool_analyticsOne tool's failures and the tools agents call right before and after it

Feedback

ToolDescription
submit_feedbackSend a bug report, feature request, question or praise to the Notra inbox (no auth)
list_feedbackList feedback the organization received, by status, kind or project
get_feedbackGet one feedback entry with agent metadata
update_feedbackSet a feedback entry's triage status

Review and data boundaries

All supported operations are listed upfront by tools/list. General-purpose agent execution and approval tools are not exposed because they can run dynamically discovered third-party operations. Chat history and agent sessions are available through the dashboard and API. Use the Notra dashboard for agent conversations, private-repository authentication, webhook signing secrets, and traffic tracking credentials.

Tool inputs are for task-specific business content. Do not send health records, biometric data, government identifiers, payment card information, credentials, or unrelated conversation history. Authenticate through OAuth or local configuration, never through tool arguments. Feedback accepts only the user-approved message, optional title, and feedback kind.

Development

Use Node 22.12+ (Node 22) or Node 24 and the pnpm version pinned in package.json:

sh
corepack enable
pnpm install --frozen-lockfile
pnpm run typecheck
pnpm run format:check

Tool output schemas in src/schemas/api-responses.ts are generated from the Notra OpenAPI spec. Run pnpm run generate:output-schemas after the API changes; CI fails when the file is stale.

CI runs typechecking, formatting checks, and the build on pull requests and pushes to main.