circle-so-mcp
v0.3.1
Published
MCP server for Circle.so Admin API v2 — community intelligence and content management tools for spaces, posts, members, comments, topics, search, and derived analytics
Maintainers
Readme
Circle MCP Server
Give Claude direct access to your Circle.so community.
A Model Context Protocol (MCP) server that connects Claude Desktop — or any MCP-compatible client — to the Circle.so Admin API v2. Query spaces, posts, members, comments, and topics; detect unanswered questions; get community health snapshots; and create or update content, all through natural language.
Why This Project Exists
Circle.so is a powerful community platform, but its Admin API is designed for machines, not conversations. This server bridges that gap: it wraps the Circle API in a structured, type-safe MCP interface so that AI assistants can read, search, analyze, and write community content without custom integration code.
If you manage a Circle community and use Claude, this server lets you work with your community data conversationally — no API scripting required.
Who It's For
- Community managers who want to query their Circle community through Claude Desktop
- Developer advocates automating community monitoring (unanswered posts, health checks)
- Operators who need to create or update posts and comments programmatically via AI
- Developers building MCP-based workflows that include Circle.so data
What It Can Do Today
| Capability | Status | |------------|--------| | Read spaces, posts, members, comments, topics, space groups | ✅ Shipped | | Full-text search across community content | ✅ Shipped | | Detect unanswered posts (zero-comment heuristic) | ✅ Shipped | | Community health snapshot (aggregated counts) | ✅ Shipped | | Create and update posts | ✅ Shipped | | Create comments | ⚠️ Shipped (Circle API returns 401 for admin tokens — see Known Limitations) | | Local stdio transport (Claude Desktop, MCP Inspector) | ✅ Shipped | | Smithery Local publication | ✅ Ready | | Streamable HTTP transport | 🧪 Experimental |
Tool Coverage
16 tools across three release generations:
| Generation | Tools | Purpose |
|------------|-------|---------|
| Core Read (v0.1.0) | circle_list_spaces, circle_get_space, circle_list_posts, circle_get_post, circle_list_members, circle_search | Community data access |
| Extended Read (v0.2.0) | circle_list_comments, circle_get_comment, circle_list_topics, circle_get_community, circle_list_space_groups | Full API surface |
| Derived Intelligence (v0.2.0) | circle_detect_unanswered_posts, circle_community_health | Aggregated insights |
| Write (v0.3.0) | circle_create_post, circle_update_post, circle_create_comment | Content management |
All read tools include MCP annotations (readOnlyHint: true, idempotentHint: true). Write tools declare readOnlyHint: false, destructiveHint: false — no delete operations are exposed.
Core Read Tools (v0.1.0)
circle_list_spaces — List spaces with pagination and sorting.
page(int),per_page(int, 1–100),sort(enum)- Returns:
{ pagination, spaces[] }
circle_get_space — Get a single space by ID.
space_id(int, required)- Returns:
{ space }
circle_list_posts — List posts with filtering.
page,per_page,space_id,space_group_id,status(draft/published/scheduled/all),search_text,sort- Returns:
{ pagination, posts[] }— includes full TipTap body
circle_get_post — Get a single post by ID.
post_id(int, required)- Returns:
{ post }
circle_list_members — List members with status filtering.
page,per_page,status(omit for active,all,inactive)- Returns:
{ pagination, members[] }
circle_search — Search across the community. Returns lightweight summaries.
query(string, required),page,per_page,type(enum)- Returns:
{ pagination, results[] }— use get tools for full objects
Extended Read Tools (v0.2.0)
circle_list_comments — List comments, optionally filtered by post or space.
page,per_page,post_id,space_id- Returns:
{ pagination, comments[] }
circle_get_comment — Get a single comment by ID.
comment_id(int, required)- Returns:
{ comment }
circle_list_topics — List all topics (tags/categories).
page,per_page- Returns:
{ pagination, topics[] }
circle_get_community — Community-level metadata. No parameters.
- Returns:
{ community }— name, URL, branding, locale, settings
circle_list_space_groups — List space groups (navigational categories).
page,per_page- Returns:
{ pagination, space_groups[] }
Derived Intelligence Tools (v0.2.0)
circle_detect_unanswered_posts — Posts with zero comments.
space_id,per_page,page- Returns:
{ computation, unanswered_posts[] }
circle_community_health — Aggregated community snapshot. No parameters.
- Returns:
{ computation, community, counts, snapshot_timestamp }
Write Tools (v0.3.0)
circle_create_post — Create a post in a space.
space_id(int, required),name(string, required),body(HTML string, required),status,is_comments_enabled,is_liking_enabled,skip_notifications- Returns:
MutationResult<CirclePost>
circle_update_post — Update an existing post. Only provided fields change.
post_id(int, required),name,body,status,is_comments_enabled,is_liking_enabled- Returns:
MutationResult<CirclePost>
circle_create_comment — Create a comment on a post.
post_id(int, required),body(HTML string, required)- Returns:
MutationResult<CircleComment>
Installation
Prerequisites
- Node.js ≥ 18.0.0 (uses native
fetch) - Circle Admin API token — obtain from Circle Admin → Settings → API
- npm (bundled with Node.js)
Option 1: Clone and Build (Recommended)
git clone https://github.com/iamnortey/circle-mcp-server.git
cd circle-mcp-server
npm install
npm run build
# Verify everything works (typecheck + build + 95 offline tests)
npm run validateOption 2: npx
CIRCLE_API_TOKEN=your-token npx circle-so-mcpSetup
Claude Desktop (stdio)
Add to your Claude Desktop config file:
| Platform | Config File |
|----------|-------------|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
Production (built server):
{
"mcpServers": {
"circle": {
"command": "node",
"args": ["/absolute/path/to/circle-mcp-server/dist/index.js"],
"env": {
"CIRCLE_API_TOKEN": "your-admin-token-here"
}
}
}
}Development (hot-reload with tsx):
{
"mcpServers": {
"circle": {
"command": "npx",
"args": ["tsx", "/absolute/path/to/circle-mcp-server/src/index.ts"],
"env": {
"CIRCLE_API_TOKEN": "your-admin-token-here"
}
}
}
}Use absolute paths in the
argsarray. Claude Desktop does not set a working directory.
Smithery Local
This server includes a smithery.yaml manifest for Smithery Local publication. Smithery manages configuration and launches the server via stdio — no Docker or HTTP required.
The manifest exposes:
circleApiToken(required) — your Circle Admin API tokencircleBaseUrl(optional) — defaults tohttps://app.circle.so
MCP Inspector
Test tools interactively without Claude Desktop:
CIRCLE_API_TOKEN=your-token npx @modelcontextprotocol/inspector node dist/index.jsConfiguration
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| CIRCLE_API_TOKEN | Yes | — | Circle Admin API token (v2) |
| CIRCLE_BASE_URL | No | https://app.circle.so | Circle API base URL (override for custom/proxy deployments) |
Set these as environment variables or in a .env file (see .env.example).
Example Workflows
These are real workflows you can run today through Claude Desktop with this server connected:
Community monitoring:
"Show me all unanswered posts in the General space from this week."
Content audit:
"List all draft posts across the community and summarize their topics."
Member insight:
"How many active members do we have? Give me a community health snapshot."
Content creation:
"Create a draft post in the Announcements space titled 'Q2 Update' with a summary of our recent milestones."
Search and discovery:
"Search for posts about 'onboarding' and show me which spaces they're in."
Architecture
src/
index.ts # Entry point — stdio transport (DO NOT MODIFY)
http.ts # Entry point — Streamable HTTP transport (experimental)
server.ts # Transport-agnostic server factory
config/env.ts # Environment config with fail-fast validation
types/ # Circle domain types + shared types
lib/ # HTTP client, error normalization, response builders
schemas/inputs.ts # Zod input schemas for all 16 tools
clients/ # Typed Circle API client (11 read + 3 write methods)
tools/ # 16 tool handlers (one file per tool)flowchart LR
A[Claude Desktop / MCP Client] -->|stdio| B(index.ts)
A2[Smithery / HTTP Client] -->|HTTP| C(http.ts)
B --> D[createServer]
C --> D
D --> E[Zod Validation]
E --> F[16 Tool Handlers]
F --> G[CircleClient]
G -->|HTTPS + Retry| H[(Circle Admin API v2)]Key design decisions:
- Server factory pattern —
createServer()is decoupled from transport, enabling future HTTP support without changing tool logic - Strict Zod schemas — Every tool input is validated with
.strict()to reject unknown properties - Structured responses — All tools return both
content(human-readable text) andstructuredContent(machine-parseable data) - No delete operations — Write tools only support create and update for safety
Safety and Resilience
Response Truncation
Large API responses are guarded by prepareSafeText():
- Limit: 100,000 characters (~25,000 tokens)
- Truncates at clean line breaks with a structured notice (original/truncated sizes, pagination advice)
structuredContentis never truncated — clients that parse structured data get the full payload
Mutation Safety
- No auto-retry — Write operations use a zero-retry policy to prevent duplicate content
- No delete tools — Only create and update operations are exposed
- MCP annotations — Write tools declare
readOnlyHint: false,destructiveHint: false - Permission-aware errors — Known API limitations return clear messages with workarounds
Retry with Exponential Backoff (Read Only)
| Attempt | Delay | Retryable Statuses | |---------|-------|-------------------| | 1 (initial) | — | — | | 2 (first retry) | 1s | 429, 500, 502, 503 | | 3 (last retry) | 2s | 429, 500, 502, 503 |
Respects Retry-After headers. Network errors are also retried. Write operations never retry.
Error Handling
All errors are normalized into actionable messages:
| Status | Guidance | |--------|----------| | 401 | Verify your CIRCLE_API_TOKEN is correct and not expired | | 403 | Your API token may lack permissions for this resource | | 404 | Verify the ID exists in your Circle community | | 429 | Circle allows 2,000 requests per 5 minutes per IP |
Known Limitations
- No delete operations — Write tools support create and update only
- Comment creation restricted — Circle Admin API v2 consistently returns 401 for admin tokens on the comment creation endpoint. Use the Circle web interface to create comments. Read tools work normally.
- Published posts cannot revert to draft — Circle API constraint (returns 400)
- No mutation retry — Write operations do not auto-retry
- Search returns summaries — Use get tools for full objects
- Page-based pagination only — No cursor pagination; deep pages may be slow
- Derived tools use simple heuristics — "unanswered" means
comments_count === 0 - Community health is a point-in-time snapshot — Not trends or historical data
- No streaming — Responses are returned in full
- Streamable HTTP is experimental — stdio remains the primary, production-tested transport. HTTP mode includes basic hardening (body size limits, session caps, idle timeout, graceful shutdown) but has no auth layer and should not be exposed to untrusted networks.
Development and Testing
npm run typecheck # Type-check without building
npm run build # Production build (includes shebang injection for bin)
npm run dev # Watch mode with tsx (hot-reload)
npm run start:http # Start Streamable HTTP server (experimental, default port 3000)
npm run dev:http # Watch mode for HTTP entrypoint
npm run validate # Full validation: typecheck + build + 95 offline tests
npm test # Build + run 95 offline smoke tests
npm run test:http # Build + run HTTP endpoint smoke tests
npm run clean # Remove build artifactsTest Suite
95 offline tests — no network calls, no API token needed:
- Schema validation for all 16 tools (accepts valid input, rejects invalid, enforces
.strict()) - Response builders, error normalization, pagination extraction
- Write tool handlers, mutation response envelopes, destructuring patterns
Live tests (require CIRCLE_API_TOKEN):
- 12 tests for v0.1.0 core tools
- 7 tests for v0.2.0 extended + derived tools
- Write endpoint proving script for v0.3.0
# Live tests
CIRCLE_API_TOKEN=your-token npx tsx test/smoke-live.ts
CIRCLE_API_TOKEN=your-token npx tsx test/live-v020.tsTroubleshooting
| Symptom | Likely Cause | Fix |
|---------|-------------|-----|
| Server not listed in Claude Desktop | Config file syntax error | Validate JSON; check for trailing commas |
| "CIRCLE_API_TOKEN is required" | Token missing or empty | Add token to env block in config |
| Tool calls return 401 | Token invalid or expired | Regenerate token in Circle Admin → Settings → API |
| Tool calls return 403 | Token lacks permissions | Ensure token has Admin-level access |
| Large responses truncated | Response exceeded 100K chars | Use smaller per_page values or add filters |
| "Cannot find module" error | Build artifacts missing | Run npm run build first |
Roadmap
- Streamable HTTP hardening — Add authentication, session limits, and production readiness to the experimental HTTP transport
- Docker packaging — Containerized deployment option
- Event and course tools — Expand API coverage
- Member write tools — Create/update member profiles
- Rate-limit tracking — Proactive throttle management
- Cursor pagination — For large community traversal
Implementation Details
- Language: TypeScript (strict mode)
- Runtime: Node.js ≥ 18
- MCP SDK:
@modelcontextprotocol/sdkv1.12.1 - Validation: Zod v3.24
- Transport: stdio (primary), Streamable HTTP (experimental)
- Dependencies: 2 runtime (
@modelcontextprotocol/sdk,zod), 3 dev (@types/node,tsx,typescript)
License
MIT — see LICENSE for details.
Contributing
Issues and pull requests welcome at github.com/iamnortey/circle-mcp-server.
