MCP
@topgunbuild/mcp-server lets AI assistants read and mutate your TopGun data through the Model Context Protocol. Drop it into Claude Desktop, Cursor, or any MCP-compatible client and the assistant gains eight tools for querying, mutating, searching, and inspecting your maps.
For the broader story (how to design schemas the model can use, prompting patterns), see the Building with AI guide.
Installation and transport
The server ships as @topgunbuild/mcp-server on npm and runs over either stdio (default) or HTTP.
Stdio (Claude Desktop, Cursor)
The server starts when the host AI client spawns it. No long-running process required.
Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"topgun": {
"command": "npx",
"args": ["@topgunbuild/mcp-server"],
"env": {
"TOPGUN_URL": "ws://localhost:8080"
}
}
}
}
Cursor (~/.cursor/mcp.json):
{
"mcp": {
"servers": {
"topgun": {
"command": "npx",
"args": ["@topgunbuild/mcp-server"],
"env": {
"TOPGUN_URL": "ws://localhost:8080"
}
}
}
}
}
HTTP
For remote MCP clients or shared deployments, run the server as a long-lived HTTP service.
# Default port 3000
npx @topgunbuild/mcp-server --http --port 3000
# With auth, restricted maps, mutations disabled
npx @topgunbuild/mcp-server --http --port 3000 \
--url ws://production.example.com:8080 \
--token $TOPGUN_TOKEN \
--maps tasks,users \
--no-mutations
Programmatic API
For embedding the MCP server inside an existing Node process, use the TopGunMCPServer class.
import { TopGunMCPServer } from '@topgunbuild/mcp-server';
const server = new TopGunMCPServer({
topgunUrl: 'ws://localhost:8080',
authToken: process.env.TOPGUN_TOKEN,
allowedMaps: ['tasks', 'users', 'projects'],
enableMutations: true,
enableSubscriptions: true,
defaultLimit: 10,
maxLimit: 100,
debug: false,
});
await server.start();
MCPServerConfig fields (all optional):
| Field | Default | Description |
|---|---|---|
name | "topgun-mcp-server" | Server name advertised over MCP. |
version | "1.0.0" | Server version. |
topgunUrl | "ws://localhost:8080" | TopGun WebSocket URL. |
authToken | none | JWT passed to client.setAuthToken(). |
allowedMaps | unrestricted | Whitelist of map names the assistant may touch. |
enableMutations | true | If false, topgun_mutate returns an error. |
enableSubscriptions | true | If false, topgun_subscribe is unavailable. |
defaultLimit | 10 | Default page size for topgun_query. |
maxLimit | 100 | Hard cap on requested page size. |
subscriptionTimeoutSeconds | 60 | Maximum lifetime of a topgun_subscribe call. |
debug | false | Verbose logging. |
client | none | Pre-built TopGunClient instance (overrides topgunUrl + authToken). |
server.start() spawns the transport (stdio or HTTP) and registers tool handlers.
Tools
The server exposes eight tools, all prefixed with topgun_. The assistant chooses which to invoke based on the natural-language prompt.
topgun_list_maps
List every map the server knows about.
- Parameters: none
- Response: array of
{ name, recordCount, hasFTS, hasVectorIndex } - Security: filtered by
allowedMapswhen set
> What maps are available?
[lists tasks, users, projects]
topgun_query
Read records from a map with filters and sorting. Returns authoritative server data — the assistant gets the live, server-confirmed answer, not a stale local guess.
- Parameters:
{ map, filter?, sort?, limit?, fields? } - Response:
[{ _key, ...fields }](a plain settled array) - Security: rejects maps outside
allowedMaps; clampslimittomaxLimit
> Show me unfinished tasks created this week
[runs topgun_query with where: { done: false, createdAt: { gt: ... } }]
A settled result with no matching records renders as No results found in map '<map>'... — that means the server genuinely has no such rows, not that the query failed.
Offline / not-settled behavior. topgun_query never silently returns stale local data and never conflates “offline” with “empty”. If the server cannot be reached, or the query does not settle within the default 5000 ms window, the tool returns an error (isError: true) explaining that no authoritative data was returned — so the assistant knows to retry rather than reporting an empty list. The message distinguishes the two causes (server unreachable / client offline, vs. timed out waiting for the server).
No cursor pagination, but truncation is never silent. topgun_query returns a plain settled array; the previous nextCursor / hasMore continuation hint and cursor parameter have been removed (continuation cursors are an anti-pattern for an LLM caller). It does not drop the one signal that matters: when more rows match than the returned limit, the response appends a More rows match than were returned… note so the assistant knows the view was capped and can narrow filter / sort (or raise limit up to maxLimit) — rather than reporting a truncated list as the whole answer.
topgun_mutate
Create, update, or remove a record.
- Parameters:
{ map, op: "create" | "update" | "remove", key, value? } - Response:
{ success, key }or an error object - Security: requires
enableMutations: true; rejects maps outsideallowedMaps
> Add a task: "Write the spec response"
[runs topgun_mutate with op: 'create', value: { text: '...', done: false }]
topgun_search
BM25 full-text search across a map.
- Parameters:
{ map, query, limit?, minScore?, boost? } - Response:
[{ _key, value, score, matchedTerms }] - Security: requires FTS enabled for the map on the server
> Find tasks mentioning "deployment"
[runs topgun_search with query: 'deployment']
topgun_subscribe
Subscribe to live updates on a map for a bounded time window. Useful for the assistant to watch for changes during a conversation.
- Parameters:
{ map, filter?, durationSeconds? } - Response: stream of
{ type: 'add' | 'update' | 'remove', key, value }until timeout - Security: requires
enableSubscriptions: true; capped bysubscriptionTimeoutSeconds
topgun_schema
Inspect a map’s schema (registered field types, indexes, FTS configuration).
- Parameters:
{ map } - Response:
{ name, fields, indexes, fts?, vectorIndex? }
topgun_stats
Operational stats for a map.
- Parameters:
{ map } - Response:
{ recordCount, sizeBytes, tombstoneCount, ftsIndexSize?, vectorIndexSize? }
topgun_explain
Show the query plan and estimated cost for a query without executing it.
- Parameters:
{ map, filter?, sort?, limit? } - Response:
{ plan: PlanStep[], estimatedCost, indexesUsed }
Use this to debug why a query is slow or to confirm the planner is picking the index you expect.
Security model
Three tunables shape what the assistant can do:
| Tunable | Behavior |
|---|---|
allowedMaps | Hard whitelist. Tools refuse to operate on maps outside the list. |
enableMutations | When false, topgun_mutate returns an error before touching the database. |
enableSubscriptions | When false, topgun_subscribe is unavailable. |
For production deployments, run the MCP server with a service-scoped JWT (via authToken) so the underlying TopGun server’s authorization policies are also enforced. The MCP layer is defense-in-depth, not a substitute for proper server-side auth.