noon-sight
Allows retrieving published posts and content metadata from Buffer, supporting content reports.
Provides edge request analytics from Cloudflare, including request volumes, bytes served, and breakdowns by various dimensions.
Provides website traffic analytics from Google Analytics, including sessions, users, engagement, duration, and key events.
Provides search performance metrics from Google Search Console, including clicks, impressions, CTR, and average position.
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., "@noon-sightWhat were my top search queries this month?"
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.
noon-sight
An MCP server on Cloudflare Workers that aggregates what a site publishes and how it is read. Four sources answer four questions, and Cloudflare Zero Trust guards the door.
Deliberately small: it carries the tools that are actually used, not a full API surface.
What each source can see
published ────▶ shown ────▶ requested ────▶ rendered
│ │ │ │
Buffer Search Console Cloudflare Google Analytics
│ │ │ │
content_report search_report request_report traffic_reportA source earns its place by answering what the others structurally cannot.
Source | Sees | Blind to |
Buffer | what was published, before anyone read it | anything posted outside Buffer |
Search Console | everyone shown the site, whether they came or not | everyone who arrived from anywhere but Google |
Cloudflare | every request at the edge, JavaScript or not | what happened inside the page, and last week |
Google Analytics | whoever arrived and rendered the page | anyone who ran no JavaScript |
Every figure is what one measurement system saw, not what happened. Two sources disagreeing does not make either wrong.
Related MCP server: SEOMonster
Tools
Tool | Source | Answers with |
| Other input | Default window |
| Google Analytics | sessions, users, engagement, duration, key events |
|
| 28 days, paired |
| Google Search Console | clicks, impressions, CTR, average position |
|
| 28 days, paired |
| Cloudflare zone analytics | requests and bytes at the edge |
|
| 7 days, paired if kept |
| Buffer, and the pages themselves | the posts themselves, with what each page declares it is about | — |
| 28 days, unpaired |
The first three count, and every row is a pair: the requested period against the equally long one before it, because whether a number rose is what a count is for. Where a source no longer holds the earlier period, that side reads null — no record, rather than no traffic.
content_report does not count. A single post is already the whole of what it says, so it hands back the posts themselves and leaves the counting to whoever asked.
How to read any of it arrives with the handshake, as MCP instructions.
How a request flows
┌──────────────┐
│ MCP client │ Claude, or anything that speaks MCP
└──────┬───────┘
│ 401 challenge → OAuth → Access policy evaluated
┌──────▼──────────────────────┐
│ Cloudflare Access │ Managed OAuth, one application
└──────┬──────────────────────┘
│ POST /mcp + Cf-Access-Jwt-Assertion
┌──────▼──────────────────────────────────────────────┐
│ Worker — noon-sight │
│ Hono /mcp → jose verifies iss + aud → MCP server │
└───┬──────────┬───────────┬────────────┬─────────────┘
│ │ │ │
Analytics Search Cloudflare Buffer GraphQL
Data API Console GraphQL + the site's own pages
└── Service ───┘ API token API key
Account JWTAn MCP client is not a browser and cannot follow Access's 302. Managed OAuth answers it with a 401 challenge instead, resolves the token itself, and still forwards Cf-Access-Jwt-Assertion — so the Worker implements no OAuth of its own.
Two KV namespaces, both provisioned by wrangler and named after the Worker:
Binding | Holds | Gone after |
| the Google access token | its lifetime less five minutes |
| what a page declared it is about | 30 days; one that declared nothing, a day |
Setup
Access cannot be named before it exists, so the order matters at exactly one point:
pnpm deploy ────▶ Access application ────▶ TEAM_DOMAIN + POLICY_AUD ────▶ sources
▲ on that hostname Access now enforced one at a time,
│ in any order
403 "Access is not configured" until the secrets land — the intended state, not a faultEach source stands alone. A tool whose source is unconfigured stays registered and says what is missing, so one configured source is already useful — and a server half set up is told apart from a site with nothing to report.
1. The Worker
pnpm install
pnpm deployThe route in wrangler.jsonc is a custom domain; change it to your own hostname. workers.dev and preview URLs are deliberately not minted: Access is enabled per hostname, and an unguarded entrance is the failure mode.
2. Cloudflare Access
Step | Where | What |
Add the application | Zero Trust → Access → Applications | Self-hosted, on the Worker's hostname |
Add a policy | the same application | Whoever may read the site's numbers |
Turn on Managed OAuth | the application → Advanced settings | Turns Access into an OAuth server for this application, so a non-browser client can log in |
Allow the client's callback | the same tab → Allowed redirect URIs |
|
Read the AUD | the application's overview | The Application Audience tag |
Secret | Value |
|
|
| The Application Audience tag |
pnpm wrangler secret put TEAM_DOMAIN
pnpm wrangler secret put POLICY_AUDA further hostname joins this same application as an additional public hostname. A second application would mint a second AUD, and one POLICY_AUD cannot match both.
Access registers each client dynamically and keeps a refused registration, so allowlist the callback before the client first tries. Afterwards, it has to be removed and added again.
3. Google Analytics and Search Console
One Service Account serves both, and asks for nothing wider than the two read scopes.
Step | Where | What |
Enable the APIs | Google Cloud → APIs & Services | Google Analytics Data API, Google Search Console API |
Create the account and a JSON key | Google Cloud → IAM & Admin → Service Accounts | The downloaded JSON file is the secret, whole |
Grant it the GA4 property | GA4 → Admin → Property access management | Its e-mail, as Viewer |
Grant it the Search Console property | Search Console → Settings → Users and permissions | The same e-mail, Full or Restricted. Google Cloud grants nothing here — the property's own user list does |
Secret | Value |
| The whole Service Account JSON, verbatim — one secret rather than a field per value, because the private key is a PEM whose newlines survive JSON but not a shell |
| The numeric GA4 property id, from Admin → Property details |
| Whatever string |
Workers carry no Node crypto, so the official Google SDK cannot run here. jose signs the assertion, Google exchanges it for a bearer token, and KV holds that token for its hour.
4. Cloudflare zone analytics
Step | Where | What |
Create the token | My Profile → API Tokens → Create Token → Custom |
|
Read the zone id | the zone's Overview page, under API |
Secret | Value |
| The token as it stands — it is the credential rather than a claim to be exchanged for one, so nothing is signed or cached |
| The zone the site lives in |
| The hostname this server answers for, e.g. |
A zone is a billing boundary carrying every hostname under it, so this source takes two identifiers where the others take one. CLOUDFLARE_SITE_HOST narrows a request report to one site, and tells a link to this site from a link anywhere else. Left unset, the report covers the whole zone.
Refusals arrive as 200 with an errors array, so a token without the permission looks like success to anything reading the status. The tool reads the array and repeats what Cloudflare said.
5. Buffer
Step | Where | What |
Create the API key | ||
Find the organization id | one query, below | An account may hold several, and every Buffer query names one |
curl -s https://api.buffer.com \
-H "Authorization: Bearer $BUFFER_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"query":"{ account { organizations { id name } } }"}'Secret | Value |
| The key as it stands, like Cloudflare's |
| The |
Naming the organization here makes it the same kind of value as the property and the zone, and spares every report the round trip that would otherwise start it.
content_report then asks each linked page what it is about — Accept: text/markdown first, then schema.org in the HTML — which is why it also needs CLOUDFLARE_SITE_HOST. A page declaring nothing is reported as declaring nothing.
Every secret at a glance
Secret | Unlocks | Without it |
| every request |
|
|
| both refuse, saying Google credentials are not configured |
|
| it refuses, saying no property is configured |
|
| it refuses, saying no property is configured |
|
| it refuses, naming the one that is missing |
|
| the zone answers whole, and no post is recognised as this site's |
|
| it refuses, naming the one that is missing |
Secrets live in wrangler secret and .dev.vars, never in wrangler.jsonc. Cloudflare classes the first two as vars rather than secrets, but keeping them out of the repository publishes neither the team nor the application being guarded.
Local development
.dev.vars carries the same names, plus DEBUG=true, which skips Access verification — local development has no Access in front of it. Production reads no such flag and therefore denies; vitest pins it off, so no local file can disarm the suite.
Command | Does |
| Runs locally on workerd, reading |
| Runs the suite on workerd, outbound requests answered by MSW |
| Typechecks |
| Prettier; |
| Deploys to Cloudflare |
| Regenerates binding types; run after changing |
Connecting a client
Add https://<your-hostname>/mcp as a remote MCP server. The first call is answered with a 401 naming Access's OAuth endpoints; the client registers itself and walks the flow, and Access evaluates its policy before anything reaches the Worker.
License
Apache-2.0
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseBqualityDmaintenanceAn MCP server that integrates Google Search Console and Google Analytics 4 to provide unified SEO and web traffic analysis. It allows users to fetch search performance data, merge page metrics, and generate automated trend reports or actionable insights through tool calls.16
- AlicenseAqualityAmaintenanceSEO MCP over Search Console, GA4, PageSpeed, Cloudflare, IndexNow, CrUX, and 7 technical-SEO HTTP tools.702MIT
- Alicense-qualityAmaintenanceOAuth-protected Google Search Console MCP for analytics, URL inspection, sitemap management, indexing requests, and SEO diagnostics. Open-source Cloudflare Workers implementation with 17 tools.202MIT
- Flicense-qualityCmaintenanceEnables MCP clients to read Google Analytics 4 data, deployed as a Cloudflare Worker with service account authentication.1
Related MCP Connectors
Cloud MCP for project data, analytics, research, content planning, media generation, and growth.
Turn Search Console data into SEO actions, content, publishing, indexing, and AI insights.
One MCP for 160+ live web-data APIs — clean JSON from sites that block scrapers.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/elct9620/noon-sight'
If you have feedback or need assistance with the MCP directory API, please join our Discord server