@playscope/mcp
v0.2.9
Published
Read-only MCP server exposing PlayScope session data to AI agents (Claude, GPT, etc.).
Maintainers
Readme
@playscope/mcp
Read-only MCP server that exposes PlayScope session data to AI agents. The server itself is provider-agnostic — it stores no AI API keys and does no LLM calls. Spec: MCP Server Specification.
Status — 0.2.0. Foundation, ten read-only tools (PSDK-35/52/36), and RFC 8628 Device Authorization Grant + persistent credentials so a developer can
playscope-mcp loginonce and never paste a token by hand again.
Transports
| Mode | Use | Auth |
| --- | --- | --- |
| stdio | Claude Code, Claude Desktop, any local MCP client | PLAYSCOPE_MCP_TOKEN env var |
| sse | Cloud SaaS — mcp.playscope.dev behind nginx + TLS | Authorization: Bearer <ps_mcp_…> header on the inbound MCP connection |
Run locally — stdio
nvm use # node 22
npx -y @playscope/mcp login # opens the dashboard, RFC 8628 device flowThen ~/.claude/mcp.json (no secrets in this file — the CLI keeps tokens at
~/.config/playscope/credentials.json, file mode 0600):
{
"mcpServers": {
"playscope": {
"command": "npx",
"args": ["-y", "@playscope/mcp"]
}
}
}When the access token expires (24h) the server refreshes it silently with the
30-day refresh token. Revoke from Settings → MCP tokens or with
playscope-mcp logout.
Other commands:
playscope-mcp whoami # show stored-credentials state
playscope-mcp logout # remove credentials
playscope-mcp login --force # re-authenticate (overwrites)Run in Docker — SSE
docker run --rm -p 3100:3100 \
-e PLAYSCOPE_API_BASE_URL=https://api.playscope.dev \
-e MCP_TRANSPORT=sse \
ghcr.io/flamehand/playscope-mcp:latestBehind nginx, terminate TLS on mcp.playscope.dev and proxy /sse and
/messages to 127.0.0.1:3100. Health probes: GET /health/live,
GET /health/ready.
Layout
src/
index.ts entrypoint — picks transport, wires logging
config.ts env parsing
logging.ts JSON-to-stdout/stderr structured logger
limits.ts per-tool query caps (Spec §4)
conventions.ts response-shape conventions + error mapping (Spec §10)
server.ts McpServer factory + ToolContext type
transports/
stdio.ts StdioServerTransport
sse.ts Express + SSEServerTransport
backend/
client.ts fetch wrapper for the PlayScope backend
auth.ts StaticAuth (stdio) / SlotAuth (SSE)Phase 8c — adding a tool
Each tool is a thin file under src/tools/<tool>.ts. The skeleton:
import { z } from "zod";
import { wrapTool } from "../conventions.js";
import type { ToolContext } from "../server.js";
export const inputSchema = z.object({ project_id: z.string().uuid(), /* ... */ });
export function register(server: McpServer, ctx: ToolContext): void {
server.registerTool(
"get_session",
{ description: "Get full metadata for a session.", inputSchema },
async (rawInput) => {
const input = inputSchema.parse(rawInput);
return toMcpContent(
await wrapTool("get_session", input, ctx.logger, async (i) => {
const auth = ctx.auth.resolveAuth();
return ctx.backend.get(`/v1/projects/${i.project_id}/sessions/${i.session_id}`, auth);
}),
);
},
);
}registerTools(server, ctx) is called from createServer once the ten tools
exist.
Tests
npm testVitest unit tests cover the convention/limit helpers and the backend client's
error mapping. Integration tests against a real backend live under
test/integration/ and require PLAYSCOPE_TEST_* env vars.
