{"_id":"cituna-mcp","_rev":"6-3854155b0dd985cea40f86fa6de92209","name":"cituna-mcp","dist-tags":{"latest":"1.8.0"},"versions":{"1.0.0":{"name":"cituna-mcp","version":"1.0.0","keywords":["mcp","modelcontextprotocol","ai-visibility","aeo","geo","google-search-console","seo","cituna"],"author":{"name":"Cituna"},"license":"MIT","_id":"cituna-mcp@1.0.0","maintainers":[{"name":"cituna","email":"hello@cituna.com"}],"homepage":"https://cituna.com/mcp","bugs":{"url":"https://github.com/cituna/cituna-mcp/issues"},"bin":{"cituna-mcp":"dist/index.js"},"dist":{"shasum":"ba33fabc1505b9ad4cdbfc4079b9a3cc139283f6","tarball":"https://registry.npmjs.org/cituna-mcp/-/cituna-mcp-1.0.0.tgz","fileCount":5,"integrity":"sha512-8uHulYKQtsE8qejaQORZ7k5hXGSe0s8zz3XeYb57SfMQLLkS2ATUI+iWZw0X7ox4Z0W2tbfGOVvmiDpk6PNy1A==","signatures":[{"sig":"MEQCIH1rIGF/Ipi2LZHLpqovjA0bTIuO7bQ0w1r27XK/V27aAiAOrgX2WItFuztxsgK/eEm9aBIiQYUu1rIbeD1iWuOpwg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":96193},"main":"dist/index.js","type":"module","engines":{"node":">=18.17"},"gitHead":"bb6b83acf76dd5134637c4d9013011cb2981eb9d","scripts":{"dev":"tsx src/index.ts","test":"tsx src/client.test.ts","build":"tsc","start":"node dist/index.js","postversion":"cd .. && git add mcp/package.json mcp/package-lock.json && git commit -m \"release: cituna-mcp v$npm_package_version\" && git tag mcp-v$npm_package_version && echo \"tagged mcp-v$npm_package_version — now: git push --follow-tags\"","prepublishOnly":"npm run build"},"_npmUser":{"name":"cituna","email":"hello@cituna.com"},"repository":{"url":"git+https://github.com/cituna/cituna-mcp.git","type":"git"},"_npmVersion":"11.12.1","description":"MCP server for Cituna: daily AI-visibility tracking (per-engine citations, positions, and the answer receipts), audits, gaps, and live Google Search Console data, for Claude and other MCP clients.","directories":{},"_nodeVersion":"24.15.0","dependencies":{"@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.1","typescript":"^5.6.2","@types/node":"^22.7.0"},"_npmOperationalInternal":{"tmp":"tmp/cituna-mcp_1.0.0_1785779007832_0.3654192484319154","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"cituna-mcp","version":"1.0.1","keywords":["mcp","modelcontextprotocol","ai-visibility","aeo","geo","google-search-console","seo","cituna"],"author":{"name":"Cituna"},"license":"MIT","_id":"cituna-mcp@1.0.1","maintainers":[{"name":"cituna","email":"hello@cituna.com"}],"homepage":"https://cituna.com/mcp","bugs":{"url":"https://github.com/cituna/cituna-mcp/issues"},"bin":{"cituna-mcp":"dist/index.js"},"dist":{"shasum":"1e8fbe5aa16d4c046b0369b504df978091617002","tarball":"https://registry.npmjs.org/cituna-mcp/-/cituna-mcp-1.0.1.tgz","fileCount":5,"integrity":"sha512-xWqKk5SrNtmwCXe/9HXeNpFQ9WTDK40mDZ6yI8w+2q8xMOz+AbsRCcU0Msutyva5Wb5Lk19qvJWNvVAsUzWjfA==","signatures":[{"sig":"MEYCIQCcNWLwf+AkOY1NyukJwj82SKMtqblCbVULsnEHWfLlOAIhAJStAD8lbxe2mC1h7uEIueshVd5Jes+JRJJmytqEvbcO","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":96231},"main":"dist/index.js","type":"module","engines":{"node":">=18.17"},"gitHead":"653a67677927e5331f361b2b0854544128a2c83c","mcpName":"com.cituna/cituna-mcp","scripts":{"dev":"tsx src/index.ts","test":"tsx src/client.test.ts","build":"tsc","start":"node dist/index.js","postversion":"cd .. && git add mcp/package.json mcp/package-lock.json && git commit -m \"release: cituna-mcp v$npm_package_version\" && git tag mcp-v$npm_package_version && echo \"tagged mcp-v$npm_package_version — now: git push --follow-tags\"","prepublishOnly":"npm run build"},"_npmUser":{"name":"cituna","email":"hello@cituna.com"},"repository":{"url":"git+https://github.com/cituna/cituna-mcp.git","type":"git"},"_npmVersion":"11.12.1","description":"MCP server for Cituna: daily AI-visibility tracking (per-engine citations, positions, and the answer receipts), audits, gaps, and live Google Search Console data, for Claude and other MCP clients.","directories":{},"_nodeVersion":"24.15.0","dependencies":{"@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.1","typescript":"^5.6.2","@types/node":"^22.7.0"},"_npmOperationalInternal":{"tmp":"tmp/cituna-mcp_1.0.1_1785783871206_0.7994477033526866","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"cituna-mcp","version":"1.5.0","keywords":["mcp","modelcontextprotocol","ai-visibility","aeo","geo","google-search-console","seo","cituna"],"author":{"name":"Cituna"},"license":"MIT","_id":"cituna-mcp@1.5.0","maintainers":[{"name":"cituna","email":"hello@cituna.com"}],"homepage":"https://cituna.com/mcp","bugs":{"url":"https://github.com/cituna/cituna-mcp/issues"},"bin":{"cituna-mcp":"dist/index.js","cituna-mcp-http":"dist/http.js"},"dist":{"shasum":"25837e219d452efb298a4dad83bbda4a1890f75b","tarball":"https://registry.npmjs.org/cituna-mcp/-/cituna-mcp-1.5.0.tgz","fileCount":7,"integrity":"sha512-+LfILby2hPYkImpkIeNObrRlVgLBQWKA8YXdYpJMalWElIjheJdp5qhk6XFoaKSCMXnK98c7AumxKcOLFvIJ+g==","signatures":[{"sig":"MEYCIQD/Et7mrHbe1eP6Pctala1j5c4n+Mm9345XxEDRLJLb8wIhAJ6TNld8GGoPEF41Vj/kUp5fxQJ2YSMWx5bCAU8kD8B5","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":184286},"main":"dist/index.js","type":"module","engines":{"node":">=18.17"},"gitHead":"d1cbf3f1f6c3960735fc1cd28ce8fe44a93d39b2","mcpName":"com.cituna/cituna-mcp","scripts":{"dev":"tsx src/index.ts","test":"tsx src/client.test.ts && tsx src/analysis.test.ts && tsx src/routes.test.ts","build":"tsc","start":"node dist/index.js","dev:http":"tsx src/http.ts","start:http":"node dist/http.js","postversion":"cd .. && git add mcp/package.json mcp/package-lock.json && git commit -m \"release: cituna-mcp v$npm_package_version\" && git tag mcp-v$npm_package_version && echo \"tagged mcp-v$npm_package_version — now: git push --follow-tags\"","prepublishOnly":"npm run build","test:transports":"tsx src/transports.test.ts","test:annotations":"tsx src/annotations.test.ts"},"_npmUser":{"name":"cituna","email":"hello@cituna.com"},"repository":{"url":"git+https://github.com/cituna/cituna-mcp.git","type":"git"},"_npmVersion":"11.12.1","description":"MCP server for Cituna: daily AI-visibility tracking (per-engine citations, positions, and the answer receipts), audits, gaps, and live Google Search Console data, for Claude and other MCP clients.","directories":{},"_nodeVersion":"24.15.0","dependencies":{"@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.1","typescript":"^5.6.2","@types/node":"^22.7.0"},"_npmOperationalInternal":{"tmp":"tmp/cituna-mcp_1.5.0_1787660158600_0.22339357559379502","host":"s3://npm-registry-packages-npm-production"}},"1.6.0":{"name":"cituna-mcp","version":"1.6.0","keywords":["mcp","modelcontextprotocol","ai-visibility","aeo","geo","google-search-console","seo","cituna"],"author":{"name":"Cituna"},"license":"MIT","_id":"cituna-mcp@1.6.0","maintainers":[{"name":"cituna","email":"hello@cituna.com"}],"homepage":"https://cituna.com/mcp","bugs":{"url":"https://github.com/cituna/cituna-mcp/issues"},"bin":{"cituna-mcp":"dist/index.js","cituna-mcp-http":"dist/http.js"},"dist":{"shasum":"14d3a1d29e086299078beeb8e1c3830108f924ca","tarball":"https://registry.npmjs.org/cituna-mcp/-/cituna-mcp-1.6.0.tgz","fileCount":7,"integrity":"sha512-J0T5m0joeax/L2CwB0SxTgnzav1KLHif+prtsQpT34qe/ls1pBw0n4mdLAHmbPOLfnq1Bm7TuoLkJiy1qg2wyg==","signatures":[{"sig":"MEYCIQD4rzjaANoOpOBmORQiqtAxonTSnfZ/JJdbRhCVTHpBEAIhAMfIC736T14qok91v2RKV6tAR/Cmwrn0/fyLcBuLjqRG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIDC5mPlIW/cMqFnFaNzS80kcbHeAJ8Ra7bo8xbjC3bYEAiEA2IwhgezIrTZTfR4CMUH1mFUpcuexo6ckk33SiSw0v8E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":219185},"main":"dist/index.js","type":"module","engines":{"node":">=18.17"},"mcpName":"com.cituna/cituna-mcp","scripts":{"dev":"tsx src/index.ts","test":"tsx src/client.test.ts && tsx src/analysis.test.ts && tsx src/routes.test.ts && tsx src/outreach.test.ts && tsx src/version.test.ts","build":"tsc","start":"node dist/index.js","dev:http":"tsx src/http.ts","start:http":"node dist/http.js","postversion":"cd .. && git add mcp/package.json mcp/package-lock.json && git commit -m \"release: cituna-mcp v$npm_package_version\" && git tag mcp-v$npm_package_version && echo \"tagged mcp-v$npm_package_version — now: git push --follow-tags\"","prepublishOnly":"npm run build","test:transports":"tsx src/transports.test.ts","test:annotations":"tsx src/annotations.test.ts"},"_npmUser":{"name":"cituna","email":"hello@cituna.com"},"repository":{"url":"git+https://github.com/cituna/cituna-mcp.git","type":"git"},"_npmVersion":"11.17.0","description":"MCP server for Cituna: daily AI-visibility tracking (per-engine citations, positions, and the answer receipts), audits, gaps, and live Google Search Console data, for Claude and other MCP clients.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.1","typescript":"^5.6.2","@types/node":"^22.7.0"},"_npmOperationalInternal":{"tmp":"tmp/cituna-mcp_1.6.0_1790095353703_0.3650018378684381","host":"s3://npm-registry-packages-npm-production"}},"1.7.0":{"name":"cituna-mcp","version":"1.7.0","keywords":["mcp","modelcontextprotocol","ai-visibility","aeo","geo","google-search-console","seo","cituna"],"author":{"name":"Cituna"},"license":"MIT","_id":"cituna-mcp@1.7.0","maintainers":[{"name":"cituna","email":"hello@cituna.com"}],"homepage":"https://cituna.com/mcp","bugs":{"url":"https://github.com/cituna/cituna-mcp/issues"},"bin":{"cituna-mcp":"dist/index.js","cituna-mcp-http":"dist/http.js"},"dist":{"shasum":"38fdb528a0fd5c38e587429f810e536d90773a43","tarball":"https://registry.npmjs.org/cituna-mcp/-/cituna-mcp-1.7.0.tgz","fileCount":7,"integrity":"sha512-Yyn3nkDQ4NDnR91vknOP7v5L4gCUWaqAXehLXW2Z9Rcc+yoYaGHxWqMl9WdMUewV5Sk8VoqmMHuKBVvnNKNkMA==","signatures":[{"sig":"MEUCIHMT8TgeHYEby2P1GqNPc0tCI58p0YRWIhY1l916i9HwAiEAmF6h8Fx6q1AAHOTM9Y8XaTq5Fqj75pGYM5IkQoVjWr8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCC0wInld/1xKNJ5M+svCbE3j/pu9sXmWfZ5adNCF9CdAIgXSqYnSL11G1AyA0MUHrapU73N4MGGuwWlK+HlF2h674=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":224507},"main":"dist/index.js","type":"module","_from":"file:C:/Users/kevin/AppData/Local/Temp/claude/C--Users-kevin-Desktop-Git-visibility-os-app/e06b99d5-3849-490b-afeb-c5a96c594c12/scratchpad/release/cituna-mcp-1.7.0.tgz","engines":{"node":">=18.17"},"mcpName":"com.cituna/cituna-mcp","scripts":{"dev":"tsx src/index.ts","test":"tsx src/client.test.ts && tsx src/analysis.test.ts && tsx src/routes.test.ts && tsx src/outreach.test.ts && tsx src/sourcesSearch.test.ts && tsx src/version.test.ts","build":"tsc","start":"node dist/index.js","dev:http":"tsx src/http.ts","start:http":"node dist/http.js","postversion":"cd .. && git add mcp/package.json mcp/package-lock.json && git commit -m \"release: cituna-mcp v$npm_package_version\" && git tag mcp-v$npm_package_version && echo \"tagged mcp-v$npm_package_version — now: git push --follow-tags\"","prepublishOnly":"npm run build","test:transports":"tsx src/transports.test.ts","test:annotations":"tsx src/annotations.test.ts"},"_npmUser":{"name":"cituna","email":"hello@cituna.com"},"_resolved":"C:\\Users\\kevin\\AppData\\Local\\Temp\\claude\\C--Users-kevin-Desktop-Git-visibility-os-app\\e06b99d5-3849-490b-afeb-c5a96c594c12\\scratchpad\\release\\cituna-mcp-1.7.0.tgz","_integrity":"sha512-Yyn3nkDQ4NDnR91vknOP7v5L4gCUWaqAXehLXW2Z9Rcc+yoYaGHxWqMl9WdMUewV5Sk8VoqmMHuKBVvnNKNkMA==","repository":{"url":"git+https://github.com/cituna/cituna-mcp.git","type":"git"},"_npmVersion":"11.17.0","description":"MCP server for Cituna: daily AI-visibility tracking (per-engine citations, positions, and the answer receipts), audits, gaps, and live Google Search Console data, for Claude and other MCP clients.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"@modelcontextprotocol/sdk":"^1.29.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.1","typescript":"^5.6.2","@types/node":"^22.7.0"},"_npmOperationalInternal":{"tmp":"tmp/cituna-mcp_1.7.0_1790155037882_0.8961723800402075","host":"s3://npm-registry-packages-npm-production"}},"1.8.0":{"_id":"cituna-mcp@1.8.0","bin":{"cituna-mcp":"dist/index.js","cituna-mcp-http":"dist/http.js"},"bugs":{"url":"https://github.com/cituna/cituna-mcp/issues"},"dist":{"shasum":"62008b0d2c7e3be0ed5ed6d03eff1064b40a0bf3","tarball":"https://registry.npmjs.org/cituna-mcp/-/cituna-mcp-1.8.0.tgz","fileCount":9,"integrity":"sha512-wRT2YfYy+ZuPQTnZRqS+L2fP1zEMsn460ZBtUQRL8xyXTJUywaxf2IRSllZSZvj3ahaGbsW1h5NP/mn0piA1Lw==","signatures":[{"sig":"MEUCIFuPA18Uvae99gDhX8LFItX6lbqilQzLq1LOJ+FzOzpmAiEAgnti7Fj7TPeKG9QOA0Q2OZAgCz7qRmyZ3GqCjwU9Eu4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDC0fWEZDaviycz8jGU8+e5NvGIkxsQxTG5qEevNMf/rgIgHdFBc4X8QGen6HrM04FbwY37B7Ofgio8Ks8x+EMm8cI="}],"unpackedSize":251191},"main":"dist/index.js","name":"cituna-mcp","type":"module","_from":"file:C:/Users/kevin/.cituna/cituna-mcp-1.8.0.tgz","author":{"name":"Cituna"},"engines":{"node":">=20"},"license":"MIT","mcpName":"com.cituna/cituna-mcp","scripts":{"dev":"tsx src/index.ts","test":"tsx src/client.test.ts && tsx src/analysis.test.ts && tsx src/zeroClick.test.ts && tsx src/routes.test.ts && tsx src/outreach.test.ts && tsx src/sourcesSearch.test.ts && tsx src/contentQueue.test.ts && tsx src/version.test.ts && tsx src/auditEngines.test.ts && tsx src/security.test.ts","build":"tsc","start":"node dist/index.js","dev:http":"tsx src/http.ts","start:http":"node dist/http.js","postversion":"cd .. && git add mcp/package.json mcp/package-lock.json && git commit -m \"release: cituna-mcp v$npm_package_version\" && git tag mcp-v$npm_package_version && echo \"tagged mcp-v$npm_package_version — now: git push --follow-tags\"","prepublishOnly":"npm run build","test:transports":"tsx src/transports.test.ts","test:annotations":"tsx src/annotations.test.ts"},"version":"1.8.0","_npmUser":{"name":"cituna","email":"hello@cituna.com"},"homepage":"https://cituna.com/mcp","keywords":["mcp","modelcontextprotocol","ai-visibility","aeo","geo","google-search-console","seo","cituna"],"_resolved":"C:\\Users\\kevin\\.cituna\\cituna-mcp-1.8.0.tgz","_integrity":"sha512-wRT2YfYy+ZuPQTnZRqS+L2fP1zEMsn460ZBtUQRL8xyXTJUywaxf2IRSllZSZvj3ahaGbsW1h5NP/mn0piA1Lw==","repository":{"url":"git+https://github.com/cituna/cituna-mcp.git","type":"git"},"_npmVersion":"11.17.0","description":"MCP server for Cituna: daily AI-visibility tracking (per-engine citations, positions, and the answer receipts), audits, gaps, and live Google Search Console data, for Claude and other MCP clients.","directories":{},"maintainers":[{"name":"cituna","email":"hello@cituna.com"}],"_nodeVersion":"24.19.0","dependencies":{"@modelcontextprotocol/node":"^2.1.0","@modelcontextprotocol/server":"^2.2.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.19.1","typescript":"^5.6.2","@types/node":"^22.7.0","@modelcontextprotocol/client":"^2.2.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cituna-mcp_1.8.0_1790927697973_0.3611597094903036"}}},"time":{"created":"2026-08-03T17:43:27.609Z","modified":"2026-10-02T07:54:58.286Z","1.0.0":"2026-08-03T17:43:27.973Z","1.0.1":"2026-08-03T19:04:31.357Z","1.5.0":"2026-08-25T12:15:58.756Z","1.6.0":"2026-09-22T16:42:33.797Z","1.7.0":"2026-09-23T09:17:18.024Z","1.8.0":"2026-10-02T07:54:58.066Z"},"bugs":{"url":"https://github.com/cituna/cituna-mcp/issues"},"author":{"name":"Cituna"},"license":"MIT","homepage":"https://cituna.com/mcp","keywords":["mcp","modelcontextprotocol","ai-visibility","aeo","geo","google-search-console","seo","cituna"],"repository":{"url":"git+https://github.com/cituna/cituna-mcp.git","type":"git"},"description":"MCP server for Cituna: daily AI-visibility tracking (per-engine citations, positions, and the answer receipts), audits, gaps, and live Google Search Console data, for Claude and other MCP clients.","maintainers":[{"name":"cituna","email":"hello@cituna.com"}],"readme":"# Cituna MCP server\r\n\r\n[![npm](https://img.shields.io/npm/v/cituna-mcp)](https://www.npmjs.com/package/cituna-mcp)\r\n[![license](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)\r\n\r\n> **v1.1.0** — adds a **remote (Streamable HTTP) transport** alongside stdio, so\r\n> Cituna can be added as a connector by URL instead of a local `npx` process.\r\n> Both transports are built from the same tool layer (`src/tools.ts`) and a test\r\n> asserts they expose byte-identical tools, so a Connectors user and an npx user\r\n> can never see different products.\r\n>\r\n> **v1.0.1** — first public release. Twelve read tools plus four write tools, five\r\n> built-in analysis workflows, and a server that tells your client how to open a\r\n> session and which workflow answers which question. The server reports honestly\r\n> by design: the citation matrix distinguishes `cited` / `not_cited` / `not_run`\r\n> (an engine that sat a query out is not a miss), `list_audits` exposes\r\n> `scoring_epoch` so you never compare re-based scores, and `whoami` returns your\r\n> real usage meters rather than claiming a Search Console state it cannot see\r\n> (that is `gsc_status`'s job).\r\n\r\n**The AI visibility tool you use from inside the AI.** Every other tool in this\r\ncategory hands you a dashboard and leaves the thinking to you. Cituna puts the\r\nmeasurements where you already do the reasoning: ask Claude why ChatGPT never\r\nmentions you, and it can pull the answer receipts, cross-check them against what\r\nGoogle already sends you, and queue the page that fixes it, without you opening\r\na tab.\r\n\r\nBring **Cituna** into Claude (Desktop, Code, or any MCP client). This server\r\nis a thin bridge over the Cituna backend: it authenticates as you and calls\r\nthe same endpoints the app uses, so Google's OAuth refresh token and your database\r\nstay server-side and nothing sensitive lives in the MCP.\r\n\r\nIt exposes three things Claude can work with directly:\r\n\r\n- **Daily visibility tracking** — the core deliverable. Your tracked prompts are\r\n  re-asked every day across all seven engines (ChatGPT, Perplexity, Gemini, Claude,\r\n  Grok, Google AI Overviews, Google AI Mode); `get_visibility` returns the latest prompt×engine\r\n  grid (cited? which position? which mode?) plus your current score, and\r\n  `get_engine_answers` returns the receipts — what each engine actually said, the\r\n  brands it cited, and the source URLs.\r\n- **AI-visibility audits** — per-engine citation scores across all seven engines, the\r\n  query×engine citation matrix, competitors cited, and a prioritised gap/action\r\n  queue you can update from the chat.\r\n- **Live Google Search Console** — clicks / impressions / CTR / position, top\r\n  queries and pages, and arbitrary Search Analytics queries.\r\n\r\n```\r\nClaude  ⇄  (stdio or Streamable HTTP, MCP)  ⇄  this server  ⇄  (HTTPS + your key)  ⇄  Cituna backend  ⇄  AI engines + Google Search Console\r\n```\r\n\r\nTwo transports, one tool layer:\r\n\r\n| | **stdio** (`dist/index.js`) | **remote** (`dist/http.js`) |\r\n|---|---|---|\r\n| Runs | on your machine, launched by the client | as a service, reached by URL |\r\n| Needs | Node 20+ locally | nothing local |\r\n| Credential | `CITUNA_API_KEY` env var | `Authorization: Bearer` per request |\r\n| Works in | Claude Desktop, Claude Code | Claude Desktop, Claude Code, **claude.ai web + mobile** |\r\n| Ships as | the `cituna-mcp` npm package | a container (`Dockerfile`) |\r\n\r\nBoth import `src/tools.ts`, so the tool list, descriptions and schemas are\r\nliterally the same objects. `npm run test:transports` fails the build if they\r\never diverge.\r\n\r\n## Tools\r\n\r\nTwelve read tools work from **Starter** (one exception: `list_keywords` reads\r\nthe keyword dataset that is part of **Pro**); the four **write** tools — tagged\r\n**✍︎ Pro** — require **Pro** or higher (see [Plans](#plans)). The 3-day free\r\ntrial is app-only and has no MCP access.\r\n\r\n| Tool | Plan | What it does |\r\n|---|---|---|\r\n| `whoami` | Starter+ | The authenticated account (email, workspace, role), backend URL, plan (Starter/Pro/Max), and the full usage meters (per-tool used/limit, brand + prompt-pool counts). Call first to confirm the connection. Search Console state is `gsc_status`'s job, not this tool's. |\r\n| `list_audits` | Starter+ | Recent AI-visibility audits, newest first: scanId, domain, date, AI-citation score, SEO/GEO/authority scores, open-gap count, and each audit's `scoring_epoch` (score-formula version — only compare scores within the same epoch). Optional `domain` filter. |\r\n| `get_audit` | Starter+ | One audit in detail by `scanId`: overall + per-engine scores, the query×engine citation matrix (each cell explicitly `cited` / `not_cited` / `not_run`), competitors cited, top gaps, and pass/warn/fail check counts. |\r\n| `get_visibility` | Starter+ | **Daily tracking.** The latest prompt×engine grid for a `brand` (id or domain): per tracked prompt and engine — cited?, position, mode (live/value/lite/off), status — plus the current visibility score and the day it was measured. |\r\n| `get_engine_answers` | Starter+ | **The receipts.** For a `brand` + `prompt` (optional `engine`): the actual stored answer text each engine gave on the most recent day, the brands it cited, the source URLs, and your cited position. Answer text capped ~4k chars with a `truncated` flag. |\r\n| `list_gaps` | Starter+ | The fix queue for a `domain` (or `scanId`): each gap with its `gapKey`, status (todo/doing/done), title, category, impact, effort, and the concrete fix. |\r\n| `set_gap_status` | **✍︎ Pro** | Update one gap's status (`todo` / `doing` / `done`) using the `gapKey` + `domain` from `list_gaps`. |\r\n| `list_keywords` | **✍︎ Pro** data | Keywords with real search demand, each with the stage of the page behind it. Filter `stage: \"none\"` for demand you have written nothing for yet — the shortlist worth acting on. |\r\n| `list_content_queue` | Starter+ | What AutoSEO already has in flight, so you never queue a topic that is drafted or live. Pages back through every article, or one cut of them: live, review, rejected or attention. |\r\n| `queue_article` | **✍︎ Pro** | Queue a keyword so AutoSEO drafts it on the next run. Re-queueing a keyword that already has a topic returns a duplicate notice, not a second copy. |\r\n| `mark_article_published` | **✍︎ Pro** | Tell Cituna a page for a keyword is live — one you wrote yourself or published from your own CMS. Without it Cituna keeps the keyword as unwritten and offers to write a competing page. |\r\n| `run_scan` | **✍︎ Pro** | Run a **new** audit for a URL and return the completed result. Takes ~1 min and **consumes one scan** from your monthly quota. |\r\n| `gsc_status` | Starter+ | Whether GSC is connected for your workspace, the connected Google email, and your verified GSC properties. |\r\n| `list_brands` | Starter+ | Domains tracked in your workspace — handy inputs for the audit and `gsc_*` tools. |\r\n| `gsc_overview` | Starter+ | GSC summary for a domain over the last *N* days: totals (clicks/impressions/CTR/position), top queries & pages, country/device splits, and a daily series. |\r\n| `gsc_query` | Starter+ | **The flexible one.** Arbitrary Search Analytics query: any dimensions, explicit date range or trailing window, row limit, and filters. |\r\n\r\n## Plans\r\n\r\nThe MCP server is included from the **Starter** plan (**$39/mo**) and up\r\n(Starter / Pro / Max). There is\r\n**no free MCP** — the 3-day trial is app-only, and an ended trial with no plan\r\ncan't call it.\r\n\r\n**Read / write split.** On **Starter** the MCP is **read-only**: read your\r\naudits, gaps, brands, content queue, and Search Console data all you like\r\n(`list_keywords` is the one read that needs **Pro**, because the keyword dataset\r\nitself is a Pro feature). The four **write** tools — `run_scan` (spends a scan),\r\n`set_gap_status` (mutates your action queue), `queue_article` and\r\n`mark_article_published` (both drive AutoSEO) — require **Pro** or higher; on\r\nStarter you still run scans and work the queue **in the app**, just not from\r\nClaude. Every MCP call also\r\ncounts against your plan's monthly MCP-call allowance (Starter 5k / Pro 10k / Max\r\n30k). If a write tool returns *\"…is a write action — it needs the Pro/Max plan\"*,\r\nupgrade at <https://cituna.com/pricing>.\r\n\r\n## Install\r\n\r\nNo clone, no build — `npx` fetches it:\r\n\r\n```bash\r\nnpx -y cituna-mcp   # (normally launched by your MCP client, see below)\r\n```\r\n\r\nFrom source (for development):\r\n\r\n```bash\r\ngit clone https://github.com/cituna/cituna-mcp && cd cituna-mcp\r\nnpm install && npm run build   # → node dist/index.js\r\n```\r\n\r\n## Configure\r\n\r\nSet `CITUNA_API_URL` (backend base URL, default `https://cituna.com`) plus\r\n**one** auth option, checked in this priority order:\r\n\r\n1. **Personal API key — recommended.** In the app: **Integrations → \"Claude / MCP\r\n   access\" → Generate token**, copy the `cituna_sk_…` value. Long-lived, revocable in\r\n   the app, and not your password. → `CITUNA_API_KEY`\r\n2. **A session JWT.** Log into the app, DevTools → Application → Cookies, copy\r\n   `cituna_token`. Works but expires ~30 days. → `CITUNA_TOKEN`\r\n3. **Email + password.** The server logs in and auto-refreshes on expiry.\r\n   → `CITUNA_EMAIL` + `CITUNA_PASSWORD`\r\n\r\n### Claude Code\r\n\r\n```bash\r\nclaude mcp add cituna --scope user \\\r\n  --env CITUNA_API_KEY=cituna_sk_your_generated_key \\\r\n  -- npx -y cituna-mcp\r\n```\r\n(The backend URL defaults to `https://cituna.com`; add `--env CITUNA_API_URL=…`\r\nonly to point at a different backend.)\r\n\r\nThen in a Claude Code session: `/mcp` to confirm it's connected, and ask\r\n*\"what changed in my AI visibility this week?\"*\r\n\r\n### Claude Desktop\r\n\r\nEdit `claude_desktop_config.json` (Settings → Developer → Edit Config):\r\n\r\n```json\r\n{\r\n  \"mcpServers\": {\r\n    \"cituna\": {\r\n      \"command\": \"npx\",\r\n      \"args\": [\"-y\", \"cituna-mcp\"],\r\n      \"env\": {\r\n        \"CITUNA_API_KEY\": \"cituna_sk_your_generated_key\"\r\n      }\r\n    }\r\n  }\r\n}\r\n```\r\n\r\nRestart Claude Desktop. The tools appear under the **+** button in the chat box\r\n(Add files, connectors, and more).\r\n\r\n> Running from source instead of npm? Use `\"command\": \"node\"`,\r\n> `\"args\": [\"/absolute/path/to/mcp/dist/index.js\"]`.\r\n\r\n## Remote transport (connect by URL)\r\n\r\nThe stdio server above has to run on the machine Claude runs on. That rules out\r\nclaude.ai in a browser and on mobile, and it means every user needs Node. The\r\nremote transport removes both constraints: it is one long-lived HTTPS endpoint\r\nthat any MCP client can point at.\r\n\r\n### Using it\r\n\r\nIn Claude: **Customize → Connectors → Add → Add custom connector**, then paste:\r\n\r\n```\r\nhttps://mcp.cituna.com/mcp\r\n```\r\n\r\nEither sign-in option Claude offers works: the server accepts Claude's published\r\nidentity (client ID metadata documents) and dynamic client registration. On Team\r\nand Enterprise plans an owner adds the\r\nconnector under **Organization settings → Connectors**, then each member\r\nconnects it from **Customize → Connectors**.\r\n\r\nClaude discovers the authorization server, sends you to Cituna to sign in, and\r\nshows a consent screen where you choose whether it may write as well as read.\r\nNo key changes hands. Approved apps are listed under **Integrations** in the app\r\nand can be disconnected there.\r\n\r\nPrefer to pass a personal API key instead (scripts, CI, any client without OAuth\r\nsupport)? That still works:\r\n\r\n```bash\r\nclaude mcp add --transport http cituna https://mcp.cituna.com/mcp \\\r\n  --header \"Authorization: Bearer cituna_sk_your_generated_key\"\r\n```\r\n\r\nThe endpoint is `/mcp`; `GET /healthz` reports liveness, `GET /` describes the\r\nservice, `GET /.well-known/oauth-protected-resource` is the OAuth metadata\r\ndocument clients discover from the `WWW-Authenticate` header on a 401, and\r\n`GET /.well-known/mcp-config` advertises the **API-key** path so a config-aware\r\nclient can prompt for your key instead of the OAuth grant.\r\n\r\n### Listing in a directory / connecting through a gateway\r\n\r\nAn MCP directory or gateway that discovers **only** the OAuth metadata shows one\r\n\"authorize your whole Cituna workspace\" button. That is heavier than most people\r\nwant just to connect, so this server also advertises a key-based path two ways:\r\n\r\n- **Official MCP registry** — [`server.json`](./server.json) carries a `remotes`\r\n  entry that tells registry-driven clients (and directories that mirror the\r\n  registry, e.g. PulseMCP, Glama) to connect **directly** to\r\n  `https://mcp.cituna.com/mcp` and prompt for a personal API key sent as\r\n  `Authorization: Bearer …`. Nothing is routed through the directory.\r\n- **`/.well-known/mcp-config`** — lets a config-aware client (e.g. Smithery)\r\n  render a \"paste your key\" form instead of the OAuth button.\r\n\r\n**Use a per-user key, never one shared key.** Each person connecting should paste\r\n**their own** `cituna_sk_…` key (Integrations → \"Claude / MCP access\"). A key\r\nauthenticates as one workspace and one workspace only, and the remote server is\r\nstateless per request — so keys never mix. Wiring a gateway to send one operator\r\nkey for all of its users would (correctly) make every one of them act as that\r\nsingle workspace; that is a gateway-config mistake, not a supported mode.\r\n\r\n### Running it\r\n\r\n```bash\r\nnpm run build && npm run start:http    # or: npm run dev:http\r\n```\r\n\r\n| Env | Default | Purpose |\r\n|---|---|---|\r\n| `PORT` | `8080` | Listen port. |\r\n| `CITUNA_API_URL` | `https://cituna.com` | Backend base URL. |\r\n| `CITUNA_MCP_ALLOWED_HOSTS` | *(unset)* | Comma-separated `Host` allowlist (DNS-rebinding protection). Leave unset behind a proxy that already pins the host. |\r\n\r\nNote there is no `CITUNA_API_KEY` here, deliberately: the server holds **no**\r\ncredential of its own. Every request carries its own, a fresh client and MCP\r\nserver are built for it, and both are torn down when the response ends — so one\r\nuser's key can never be captured into another user's session. A request with no\r\ncredential gets `401` and cannot even list the tools.\r\n\r\nDeploy with the included `Dockerfile` (multi-stage; the runtime image carries one\r\nproduction dependency).\r\n\r\n### How the sign-in works\r\n\r\nThis server is an OAuth 2.1 **protected resource**; the **authorization server**\r\nis the Cituna API, because that is where accounts and sessions live. A client\r\nwalks the chain itself:\r\n\r\n```\r\nPOST /mcp  (no credential)\r\n  → 401 + WWW-Authenticate: Bearer resource_metadata=\"…\"\r\n      → GET https://mcp.cituna.com/.well-known/oauth-protected-resource\r\n          → names https://api.cituna.com as the authorization server\r\n              → GET  /.well-known/oauth-authorization-server\r\n              → POST /oauth/register     (dynamic client registration, RFC 7591)\r\n              → GET  /oauth/authorize    (browser: sign in, then consent)\r\n              → POST /oauth/token        (PKCE S256 required)\r\n```\r\n\r\nAccess tokens last 24 hours; refresh tokens rotate on every use, and a\r\nrotated-out refresh token that is presented again ends the whole connection, so\r\na stolen copy cannot quietly outlive the real client. When a token expires or is\r\nrevoked, `/mcp` answers HTTP 401 with `error=\"invalid_token\"`, which is the\r\nsignal for the client to refresh or sign in again. Two scopes, and both mean\r\nsomething: `cituna:read` and `cituna:write`. A write tool needs the scope **and**\r\nthe plan, so unticking the write box on the consent screen makes the connection\r\nread-only even on a plan that permits writes.\r\n\r\nA connection can use the MCP tools and nothing else. It cannot create API keys,\r\nchange your password, reach billing, invite teammates, or approve another app;\r\nthose need you signed in to the app. Tokens are only issued for Cituna's own MCP\r\nserver (RFC 8707 `resource`), so another server that names Cituna as its\r\nauthorization server cannot collect one. If you self-host this server on a\r\ndomain outside cituna.com, add its origin to `OAUTH_ALLOWED_RESOURCES` on the API\r\n(loopback addresses are always allowed).\r\n\r\n## Built-in prompts\r\n\r\nThe server ships five reusable analysis workflows via the MCP prompts API. In\r\nClaude they show up in the prompt/command picker; each one runs a worked recipe\r\nover the tools, including the joins between Search Console and the engine\r\nanswers that a generic SEO tool cannot make.\r\n\r\n| Prompt | Arguments | What it does |\r\n|---|---|---|\r\n| `why-am-i-not-cited` | `brand`, `prompt?` | Classifies every uncited prompt into invisible-everywhere vs Google-visible-but-AI-invisible vs partially-cited, with evidence from the actual engine answers and GSC |\r\n| `gsc-to-ai-gap` | `domain`, `days?` | Queries with real Google impressions where AI never cites you: the ranked AEO target list |\r\n| `competitor-teardown` | `brand`, `competitor?` | Tallies who the engines actually cite from the answer text, and diffs it against your configured competitor list |\r\n| `weekly-review` | `brand` | Wins, regressions and this week's 3 actions from audits + GSC + the gap queue. Reads only |\r\n| `prioritize-fixes` | `domain` | Re-ranks the fix queue by the GSC impressions and uncited prompts each gap touches |\r\n\r\nAll five are read-only by default; none of them triggers a paid scan on its own.\r\nYou do not have to pick one from the picker: the server tells Claude which\r\nworkflow matches which kind of question, so plain English routes itself.\r\n\r\n## What it looks like\r\n\r\nA real first conversation, once the key is set:\r\n\r\n> **You:** We sell scheduling software. Why does ChatGPT never mention us?\r\n>\r\n> **Claude:** *(whoami → Pro, 4 of 15 scans used · list_brands → acme.com ·\r\n> gsc_status → connected)* Running the not-cited diagnosis on acme.com.\r\n>\r\n> *(get_visibility)* You are cited in 3 of 18 prompt×engine cells. ChatGPT\r\n> answers all six of your category prompts and cites you in none of them.\r\n>\r\n> *(get_engine_answers on the 3 biggest)* For \"best scheduling software for\r\n> clinics\" ChatGPT cites Calendly, Acuity and a Capterra roundup. Every citation\r\n> is a third-party list. Not one is a vendor's own site, including your rivals'.\r\n>\r\n> *(gsc_query)* Google already sends you 1,240 impressions for that intent at\r\n> average position 8.4. So this is not an indexation problem.\r\n>\r\n> **The finding:** you are Google-visible and AI-invisible. ChatGPT builds that\r\n> answer out of roundups you are absent from, so no amount of on-site work moves\r\n> it. The lever is getting into those lists.\r\n>\r\n> *(list_keywords stage:\"none\")* \"scheduling software for clinics\" has demand and\r\n> no page behind it. Want me to queue it? *(queue_article)*\r\n\r\nNothing above spends a scan: it is all reads over data Cituna already collected.\r\n\r\n## Example prompts\r\n\r\n- \"How is **acme.com** doing in AI search today — which prompts and engines cite us?\" (`get_visibility`)\r\n- \"For **acme.com**, on the prompt *best CRM for dentists*, what did each engine actually say and who did they cite?\" (`get_engine_answers`)\r\n- \"What changed in my AI visibility this week?\" (uses `list_audits` → `get_audit`)\r\n- \"Which gaps are open for **acme.com**? Mark the schema one done.\" (`list_gaps` → `set_gap_status`)\r\n- \"Run a fresh visibility scan for **acme.com** and summarise the top 3 gaps.\" (`run_scan`)\r\n- \"Which AI engines cite us, and for which questions?\" (the citation matrix from `get_audit`)\r\n- \"How did **example.com** do in Search over the last 28 days?\" (`gsc_overview`)\r\n- \"Break down example.com traffic by `country`, then by `device`.\" (`gsc_query`)\r\n- \"Show queries containing 'pricing' for example.com — filter `query contains pricing`.\" (`gsc_query`)\r\n\r\n## Connecting Google Search Console\r\n\r\nThe `gsc_*` tools need a one-time connect **in the Cituna app**, not here. There\r\nis no Google OAuth in this server, by design: the browser consent flow happens in\r\nthe app, and the resulting refresh token is stored server-side only.\r\n\r\n1. In the app, open **Integrations** and click **Connect Google Search Console**\r\n   (paid plans; the trial does not include GSC).\r\n2. Google will ask to grant Cituna **read-only** Search Console access\r\n   (`webmasters.readonly`). Cituna never gets write access to anything Google.\r\n3. Pick the Google account where your domain is a **verified Search Console\r\n   property**. This is the step people miss: if the account you choose has never\r\n   verified the domain, everything connects fine and every query still comes back\r\n   empty, because Google has nothing to show that account.\r\n4. Back here, run `gsc_status`. It lists the connected account and every property\r\n   it can query. If your domain is not in that list, fix it in Search Console\r\n   (verify the property), not in Cituna.\r\n\r\nDisconnecting in the app (Integrations, Disconnect) revokes access for this\r\nserver instantly as well.\r\n\r\n## How auth reaches Google\r\n\r\nThis server never holds Google credentials. It sends your Cituna key/JWT as a\r\n`Bearer` token to the backend; the backend looks up your workspace's stored GSC\r\nrefresh token, mints a short-lived Google access token, and queries the Search\r\nConsole API. Disconnecting GSC in the app instantly cuts off this server too.\r\n\r\n## Troubleshooting\r\n\r\n| Symptom | Fix |\r\n|---|---|\r\n| `No API key configured` | No credential set. Generate a token (Integrations → Claude / MCP access) and set `CITUNA_API_KEY`. |\r\n| `API key invalid, revoked, or the account no longer has access` | API keys never expire — the key was revoked or mistyped, a session JWT (`CITUNA_TOKEN`) expired, or the account/workspace was suspended or removed. Mint a new key in the app; email/password auto-refreshes. |\r\n| `…needs a Pro plan` / `write action` | You called a write tool (`run_scan` / `set_gap_status`) on Starter or the trial, where the MCP is read-only. Run it in the app, or upgrade to Pro at <https://cituna.com/pricing>. |\r\n| `requires a paid plan (Starter/Pro/Max)` | The tool is premium-gated and your plan isn't eligible. Upgrade at <https://cituna.com/pricing>. |\r\n| `{ \"configured\": false, ... }` | GSC OAuth env isn't set on the backend, or you haven't connected GSC, or no property matches the domain. Follow the message. |\r\n| `Rate limited (HTTP 429)` | The burst/abuse ceiling — too many requests at once, or a daily hard cap. Wait the indicated seconds and retry. This is **not** your monthly plan quota: a used-up monthly quota comes back as a plan-limit message (HTTP 402) — upgrade or wait for the period reset. |\r\n| Tools don't appear | Run `npm run build`; confirm the absolute path to `dist/index.js`; check the client's MCP logs. |\r\n| `ECONNREFUSED` | Backend isn't running / wrong `CITUNA_API_URL`. |\r\n| **Remote:** `Not signed in to Cituna` (HTTP 401) | The request reached `/mcp` without a credential. Send `Authorization: Bearer cituna_sk_…` (or `X-API-Key`). An anonymous caller cannot list tools either — that is intended. |\r\n| **Remote:** 404 with *\"The MCP endpoint is /mcp\"* | The connector URL is missing the path. Use `https://<host>/mcp`, not `https://<host>`. |\r\n| **Remote:** `Your Cituna access has expired or was revoked` (HTTP 401) | The token or key no longer works. A client that supports OAuth refreshes or reopens the sign-in on its own; otherwise reconnect, or create a new key. |\r\n| **Remote:** `That is not a Cituna MCP credential` (HTTP 401) | Only `cituna_at_…` (browser sign-in) and `cituna_sk_…` (API key) are accepted. A session token copied from the web app is refused. |\r\n| `invalid_target` during sign-in | The client asked for a token for a server that is not Cituna's. Self-hosting on your own domain: add its origin to `OAUTH_ALLOWED_RESOURCES` on the API. |\r\n| `A connected app can only use Cituna's MCP tools` (HTTP 403) | Keys, password, billing and team changes need you signed in to the app in your browser. |\r\n\r\n**stdio requires Node 20+ on the client machine. The remote transport requires\r\nnothing locally.**\r\n\r\n---\r\n\r\n## About this repository\r\n\r\nThe public [cituna/cituna-mcp](https://github.com/cituna/cituna-mcp) repo is a\r\n**published mirror**, not the working tree: the server is developed in Cituna's\r\nprivate monorepo and released on tag, so the tool surface and engine list stay\r\npinned to what the API actually serves. Pull requests against the mirror can't\r\nbe merged directly, but issues are read and acted on, so please do open them.\r\n\r\nLooking for BI dashboards instead of a chat client? Cituna also ships a Looker\r\nStudio connector. See [cituna.com/integrations](https://cituna.com/integrations).\r\n\r\nMIT licensed. Bugs and requests: <https://github.com/cituna/cituna-mcp/issues>\r\n","readmeFilename":"README.md"}