@spotfitr/mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +177 -0
  2. package/dist/index.js +33 -0
  3. package/package.json +32 -0
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # @spotfitr/mcp
2
+
3
+ MCP server that exposes the Spotfitr API as tools for Claude. Allows trainers and clients to manage sessions, bookings, and clients directly from Claude Desktop or any MCP-compatible AI client.
4
+
5
+ ## Architecture decisions
6
+
7
+ **Transport: stdio (local)**
8
+
9
+ The server runs as a local subprocess of the AI client (Claude Desktop). Each user runs their own isolated process — there is no shared state between users, no open network port, and credentials never leave the user's machine except when calling the Spotfitr API.
10
+
11
+ This was chosen over an HTTP remote server because:
12
+ - No infrastructure required (no always-on server, no TLS setup)
13
+ - Security model is trivial: one process = one user, fully isolated auth state
14
+ - The target users (fitness professionals) use Claude Desktop, so npm install is feasible
15
+ - A remote HTTP server would require rewriting the auth state model to be per-session, adding OAuth, rate limiting, and ongoing hosting costs — complexity that adds no real value for this use case
16
+
17
+ **Authentication: environment variables only**
18
+
19
+ Credentials are passed exclusively via `SPOTFITR_EMAIL` and `SPOTFITR_PASSWORD` environment variables, set in the Claude Desktop config file. A `login` tool that accepted credentials as parameters was considered and rejected: tool parameters appear in Claude's conversation context and tool call logs, which would expose the password to the model and any logging infrastructure.
20
+
21
+ **Authorization: delegated to the API**
22
+
23
+ The MCP server does not enforce any role-based access control itself. It passes the JWT from the Spotfitr API to every request and lets the API enforce permissions (OWNER vs CLIENT). Tool descriptions document which role each tool requires, but enforcement happens server-side.
24
+
25
+ **Error handling: sanitized**
26
+
27
+ API errors are filtered before being returned to the LLM. Only the API's own `error` field is forwarded (e.g. "Session is full"), never raw stack traces or internal error details. This prevents leaking implementation details through the model context.
28
+
29
+ **URL security: HTTPS enforced at startup**
30
+
31
+ If `SPOTFITR_API_URL` is set to a non-HTTPS URL (and is not localhost), the server refuses to start. This prevents the JWT from being transmitted in plaintext by misconfiguration.
32
+
33
+ ## Installation
34
+
35
+ Requires Node.js 18 or later.
36
+
37
+ The package is published to npm as `@spotfitr/mcp`. Users do not need to install it manually — `npx` handles it automatically.
38
+
39
+ ### Claude Desktop
40
+
41
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
42
+
43
+ ```json
44
+ {
45
+ "mcpServers": {
46
+ "spotfitr": {
47
+ "command": "npx",
48
+ "args": ["-y", "@spotfitr/mcp"],
49
+ "env": {
50
+ "SPOTFITR_EMAIL": "your-email@example.com",
51
+ "SPOTFITR_PASSWORD": "your-password",
52
+ "SPOTFITR_API_URL": "https://api.spotfitr.com/api"
53
+ }
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ Restart Claude Desktop after saving. Claude will have access to all Spotfitr tools automatically.
60
+
61
+ ### Claude Code (CLI)
62
+
63
+ ```bash
64
+ claude mcp add spotfitr \
65
+ -e SPOTFITR_EMAIL=your-email@example.com \
66
+ -e SPOTFITR_PASSWORD=your-password \
67
+ -e SPOTFITR_API_URL=https://api.spotfitr.com/api \
68
+ -- npx -y @spotfitr/mcp
69
+ ```
70
+
71
+ ## Environment variables
72
+
73
+ | Variable | Required | Default | Description |
74
+ |----------|----------|---------|-------------|
75
+ | `SPOTFITR_EMAIL` | Yes | — | Spotfitr account email |
76
+ | `SPOTFITR_PASSWORD` | Yes | — | Spotfitr account password |
77
+ | `SPOTFITR_API_URL` | No | `http://localhost:3001/api` | Spotfitr API base URL. Must be HTTPS for non-localhost URLs. |
78
+
79
+ If `SPOTFITR_EMAIL` or `SPOTFITR_PASSWORD` are missing, the server starts but all tool calls will fail until credentials are provided. Auto-login errors are non-fatal and logged to stderr.
80
+
81
+ ## Available tools
82
+
83
+ ### Auth
84
+ | Tool | Role | Description |
85
+ |------|------|-------------|
86
+ | `get_current_user` | Any | Get the profile of the authenticated user |
87
+ | `get_auth_status` | Any | Check if the server is authenticated and see basic user info |
88
+
89
+ ### Sessions
90
+ | Tool | Role | Description |
91
+ |------|------|-------------|
92
+ | `list_sessions` | Any | List sessions within an optional date range |
93
+ | `create_session` | OWNER | Create a new individual training session |
94
+ | `update_session` | OWNER | Update date, times, capacity, or cancel a session |
95
+ | `delete_session` | OWNER | Permanently delete a session |
96
+ | `get_session_bookings` | OWNER | List all confirmed bookings for a session (with client details) |
97
+ | `get_session_attendees` | CLIENT | List names and profile pictures of confirmed attendees |
98
+
99
+ ### Session types
100
+ | Tool | Role | Description |
101
+ |------|------|-------------|
102
+ | `list_session_types` | Any | List all workout types (e.g. CrossFit, Yoga, HIIT) |
103
+ | `create_session_type` | OWNER | Create a new workout type with name, description, and color |
104
+ | `update_session_type` | OWNER | Update name, description, or color of a workout type |
105
+ | `delete_session_type` | OWNER | Delete a workout type (fails if sessions are using it) |
106
+
107
+ ### Recurrence rules
108
+ | Tool | Role | Description |
109
+ |------|------|-------------|
110
+ | `list_recurrence_rules` | OWNER | List all recurring session rules |
111
+ | `create_recurrence_rule` | OWNER | Create a recurring rule that auto-generates sessions |
112
+ | `delete_recurrence_rule` | OWNER | Delete a rule and its future unbooked sessions |
113
+
114
+ ### Clients
115
+ | Tool | Role | Description |
116
+ |------|------|-------------|
117
+ | `list_clients` | OWNER | List all active clients with their monthly booking count |
118
+ | `list_archived_clients` | OWNER | List archived (inactive) clients |
119
+ | `create_client` | OWNER | Add a new client and send them an invitation email |
120
+ | `update_client` | OWNER | Update name, email, or monthly session limit |
121
+ | `delete_client` | OWNER | Delete a client (fails if they have any bookings) |
122
+ | `archive_client` | OWNER | Deactivate a client without deleting them |
123
+ | `unarchive_client` | OWNER | Reactivate an archived client |
124
+
125
+ ### Bookings
126
+ | Tool | Role | Description |
127
+ |------|------|-------------|
128
+ | `list_my_bookings` | CLIENT | List upcoming confirmed bookings |
129
+ | `get_my_usage` | CLIENT | Get booking usage for the current month vs the session limit |
130
+ | `book_session` | CLIENT | Book a spot in a session |
131
+ | `cancel_booking` | CLIENT | Cancel a booking (subject to cancellation window) |
132
+
133
+ ### Waitlist
134
+ | Tool | Role | Description |
135
+ |------|------|-------------|
136
+ | `list_my_waitlist` | CLIENT | List sessions you are on the waitlist for |
137
+ | `join_waitlist` | CLIENT | Join the waitlist for a full session |
138
+ | `leave_waitlist` | CLIENT | Remove yourself from the waitlist |
139
+
140
+ ### Subscription
141
+ | Tool | Role | Description |
142
+ |------|------|-------------|
143
+ | `get_subscription_info` | OWNER | Get plan (FREE/PRO), status, and client usage vs limit |
144
+
145
+ ## Local development
146
+
147
+ ```bash
148
+ cd mcp
149
+ npm install
150
+ cp .env.example .env # fill in your credentials
151
+ npm run dev
152
+ ```
153
+
154
+ The dev script uses `tsx --watch` for hot reload.
155
+
156
+ To test with Claude Code locally before publishing:
157
+
158
+ ```bash
159
+ npm run build
160
+ claude mcp add spotfitr-local \
161
+ -e SPOTFITR_EMAIL=your-email@example.com \
162
+ -e SPOTFITR_PASSWORD=your-password \
163
+ -e SPOTFITR_API_URL=http://localhost:3001/api \
164
+ -- node /absolute/path/to/spotfitr/mcp/dist/index.js
165
+ ```
166
+
167
+ ## Publishing
168
+
169
+ The package is published to npm under the `@spotfitr` org scope.
170
+
171
+ ```bash
172
+ cd mcp
173
+ npm version patch # or minor / major
174
+ npm publish # runs build automatically via prepublishOnly
175
+ ```
176
+
177
+ Requires npm login with an account that has publish access to the `@spotfitr` org.
package/dist/index.js ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { autoLogin } from "./auth.js";
5
+ import { registerAllTools } from "./tools/index.js";
6
+ async function main() {
7
+ const server = new McpServer({
8
+ name: "spotfitr",
9
+ version: "0.1.0"
10
+ });
11
+ registerAllTools(server);
12
+ const email = process.env.SPOTFITR_EMAIL;
13
+ const password = process.env.SPOTFITR_PASSWORD;
14
+ const baseUrl = process.env.SPOTFITR_API_URL ?? "http://localhost:3001/api";
15
+ if (email && password) {
16
+ try {
17
+ await autoLogin(baseUrl, email, password);
18
+ } catch (err) {
19
+ process.stderr.write(`[spotfitr-mcp] Auto-login failed: ${err.message}
20
+ `);
21
+ }
22
+ } else {
23
+ process.stderr.write("[spotfitr-mcp] No credentials provided. Call the login tool to authenticate.\n");
24
+ }
25
+ const transport = new StdioServerTransport();
26
+ await server.connect(transport);
27
+ process.stderr.write("[spotfitr-mcp] Server running on stdio\n");
28
+ }
29
+ main().catch((err) => {
30
+ process.stderr.write(`[spotfitr-mcp] Fatal error: ${err.message}
31
+ `);
32
+ process.exit(1);
33
+ });
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@spotfitr/mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server exposing the Spotfitr fitness API as tools for Claude",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "spotfitr-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "engines": {
14
+ "node": ">=18"
15
+ },
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "dev": "tsx --watch src/index.ts",
19
+ "start": "node dist/index.js",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "dependencies": {
23
+ "@modelcontextprotocol/sdk": "^1.12.0",
24
+ "zod": "^3.24.0"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^22.0.0",
28
+ "tsup": "^8.5.1",
29
+ "tsx": "^4.19.0",
30
+ "typescript": "^5.7.0"
31
+ }
32
+ }