spaps-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.
@@ -0,0 +1,351 @@
1
+ # SPAPS Integration Step 3/12: SDK Initialization
2
+
3
+ ## Prerequisites Check
4
+
5
+ Before starting, confirm you have completed:
6
+ - ✅ Step 1: Dependencies installed including spaps-sdk
7
+ - ✅ Step 2: Environment variables configured with port 3301
8
+ - ✅ SPAPS running on localhost:3301
9
+
10
+ ## Required TodoWrite List
11
+
12
+ Create a TodoWrite with EXACTLY these items:
13
+
14
+ ```javascript
15
+ TodoWrite({
16
+ todos: [
17
+ { content: "Create lib directory in project root", status: "pending", activeForm: "Creating lib directory" },
18
+ { content: "Create lib/spaps.ts file", status: "pending", activeForm: "Creating SDK initialization file" },
19
+ { content: "Import SweetPotatoSDK from 'spaps-sdk'", status: "pending", activeForm: "Importing SDK" },
20
+ { content: "Initialize SDK with localhost:3301", status: "pending", activeForm: "Initializing SDK with correct port" },
21
+ { content: "Export TokenManager and WalletUtils", status: "pending", activeForm: "Exporting utilities" },
22
+ { content: "Create type definitions if needed", status: "pending", activeForm: "Creating type definitions" },
23
+ { content: "Verify imports work correctly", status: "pending", activeForm: "Verifying SDK setup" },
24
+ { content: "Request step 4 of SPAPS integration wizard", status: "pending", activeForm: "Requesting next step" }
25
+ ]
26
+ })
27
+ ```
28
+
29
+ ## SDK Initialization Guide
30
+
31
+ ### 1. Create Directory Structure
32
+
33
+ ```bash
34
+ # From your project root
35
+ mkdir -p lib
36
+ touch lib/spaps.ts
37
+ ```
38
+
39
+ ### 2. Basic SDK Initialization
40
+
41
+ ⚠️ **CRITICAL PARAMETER NAME**: The constructor parameter is `apiUrl` (NOT `baseURL`)
42
+
43
+ Create `lib/spaps.ts` with this EXACT content:
44
+
45
+ ```typescript
46
+ // lib/spaps.ts
47
+ import { SweetPotatoSDK, TokenManager, WalletUtils } from 'spaps-sdk';
48
+
49
+ // Initialize the SDK with environment variables
50
+ // ✅ CORRECT: Use 'apiUrl' as the parameter name
51
+ const sdk = new SweetPotatoSDK({
52
+ apiUrl: process.env.NEXT_PUBLIC_SPAPS_API_URL || 'http://localhost:3301',
53
+ apiKey: process.env.SPAPS_API_KEY || 'test_key_local_dev_only'
54
+ });
55
+
56
+ // Export everything needed
57
+ export { sdk, TokenManager, WalletUtils };
58
+ export default sdk;
59
+ ```
60
+
61
+ ### Common Parameter Naming Mistakes
62
+
63
+ ❌ **WRONG** - These parameter names DO NOT WORK:
64
+ ```typescript
65
+ // WRONG - 'baseURL' doesn't exist
66
+ const sdk = new SweetPotatoSDK({
67
+ baseURL: 'http://localhost:3301', // NO!
68
+ apiKey: 'your_key'
69
+ });
70
+
71
+ // WRONG - 'url' doesn't exist
72
+ const sdk = new SweetPotatoSDK({
73
+ url: 'http://localhost:3301', // NO!
74
+ apiKey: 'your_key'
75
+ });
76
+
77
+ // WRONG - 'endpoint' doesn't exist
78
+ const sdk = new SweetPotatoSDK({
79
+ endpoint: 'http://localhost:3301', // NO!
80
+ apiKey: 'your_key'
81
+ });
82
+ ```
83
+
84
+ ✅ **CORRECT** - Always use `apiUrl`:
85
+ ```typescript
86
+ // CORRECT - This is the only parameter name that works
87
+ const sdk = new SweetPotatoSDK({
88
+ apiUrl: 'http://localhost:3301', // YES!
89
+ apiKey: 'your_key'
90
+ });
91
+ ```
92
+
93
+ ### 3. Advanced Setup (Optional)
94
+
95
+ For more control, you can create separate client and server instances:
96
+
97
+ ```typescript
98
+ // lib/spaps.ts
99
+ import { SweetPotatoSDK, TokenManager, WalletUtils, SweetPotatoAPIError } from 'spaps-sdk';
100
+ import type { AuthResponse, User } from 'spaps-sdk';
101
+
102
+ // Client-side SDK (for browser)
103
+ const clientSDK = new SweetPotatoSDK({
104
+ apiUrl: process.env.NEXT_PUBLIC_SPAPS_API_URL || 'http://localhost:3301',
105
+ apiKey: 'test_key_local_dev_only' // Public key for client
106
+ });
107
+
108
+ // Server-side SDK (for API routes/server actions)
109
+ const serverSDK = new SweetPotatoSDK({
110
+ apiUrl: process.env.NEXT_PUBLIC_SPAPS_API_URL || 'http://localhost:3301',
111
+ apiKey: process.env.SPAPS_API_KEY || 'test_key_local_dev_only'
112
+ });
113
+
114
+ // Determine which SDK to use based on environment
115
+ const sdk = typeof window !== 'undefined' ? clientSDK : serverSDK;
116
+
117
+ // Export everything applications need
118
+ export {
119
+ sdk,
120
+ clientSDK,
121
+ serverSDK,
122
+ TokenManager,
123
+ WalletUtils,
124
+ SweetPotatoAPIError
125
+ };
126
+
127
+ // Export types
128
+ export type { AuthResponse, User };
129
+
130
+ // Default export
131
+ export default sdk;
132
+ ```
133
+
134
+ ### 4. Type Definitions (if needed)
135
+
136
+ If TypeScript can't find types, create:
137
+
138
+ ```typescript
139
+ // types/spaps.d.ts
140
+ declare module 'spaps-sdk' {
141
+ export class SweetPotatoSDK {
142
+ constructor(config: { apiUrl: string; apiKey: string });
143
+ auth: AuthService;
144
+ payments: PaymentsService;
145
+ }
146
+
147
+ export class TokenManager {
148
+ static storeTokens(tokens: AuthResponse): void;
149
+ static getAccessToken(): string | null;
150
+ static getRefreshToken(): string | null;
151
+ static clearTokens(): void;
152
+ static isTokenExpired(token: string): boolean;
153
+ static autoRefreshToken(sdk: SweetPotatoSDK): Promise<boolean>;
154
+ }
155
+
156
+ export class WalletUtils {
157
+ static detectChainType(address: string): string;
158
+ static validateAddress(address: string, chainType: string): boolean;
159
+ }
160
+
161
+ export class SweetPotatoAPIError extends Error {
162
+ code?: string;
163
+ status?: number;
164
+ }
165
+
166
+ // Add other types as needed
167
+ }
168
+ ```
169
+
170
+ ### 5. Test Your Setup
171
+
172
+ Create a test file to verify the SDK works:
173
+
174
+ ```typescript
175
+ // app/api/test-sdk/route.ts
176
+ import { NextResponse } from 'next/server';
177
+ import { sdk } from '@/lib/spaps';
178
+
179
+ export async function GET() {
180
+ try {
181
+ // Test that SDK is initialized
182
+ const sdkInfo = {
183
+ initialized: !!sdk,
184
+ hasAuth: !!sdk.auth,
185
+ hasPayments: !!sdk.payments,
186
+ apiUrl: process.env.NEXT_PUBLIC_SPAPS_API_URL
187
+ };
188
+
189
+ return NextResponse.json({
190
+ success: true,
191
+ sdk: sdkInfo
192
+ });
193
+ } catch (error: any) {
194
+ return NextResponse.json({
195
+ success: false,
196
+ error: error.message
197
+ });
198
+ }
199
+ }
200
+ ```
201
+
202
+ Test it:
203
+ ```bash
204
+ curl http://localhost:3000/api/test-sdk
205
+ ```
206
+
207
+ ## Important SDK Details
208
+
209
+ ### Available SDK Methods
210
+
211
+ The SDK provides these main services:
212
+
213
+ ```typescript
214
+ sdk.auth // Authentication methods
215
+ sdk.payments // Stripe payment methods
216
+ ```
217
+
218
+ ### What's NOT in the Main SDK
219
+
220
+ Remember these are NOT in the main SDK:
221
+ - ❌ `sdk.whitelist` - Use admin-utils or direct API
222
+ - ❌ `sdk.admin` - Use direct API calls with JWT
223
+ - ❌ `sdk.users` - User management via auth methods
224
+
225
+ ### Utility Classes Available
226
+
227
+ These utilities are exported separately:
228
+ - `TokenManager` - Token storage and management
229
+ - `WalletUtils` - Wallet address utilities
230
+ - `SweetPotatoAPIError` - Error handling class
231
+
232
+ ## Validation Checklist
233
+
234
+ ✅ **File Structure**:
235
+ - `lib/spaps.ts` exists
236
+ - Imports from 'spaps-sdk' (NOT @sweet-potato/sdk)
237
+ - Exports sdk, TokenManager, WalletUtils
238
+
239
+ ✅ **SDK Configuration**:
240
+ - Uses `http://localhost:3301` as API URL
241
+ - Port is 3301 (NOT 3000, 3300, or 3456)
242
+ - API key configured correctly
243
+
244
+ ✅ **Testing**:
245
+ - Test endpoint returns success
246
+ - SDK methods are accessible
247
+ - No import errors in console
248
+
249
+ ## Common Mistakes to Avoid
250
+
251
+ ❌ **Wrong package name**:
252
+ ```typescript
253
+ // WRONG
254
+ import { SweetPotatoSDK } from 'spaps-sdk';
255
+ import { SweetPotatoSDK } from 'sweetpotato-sdk';
256
+ ```
257
+
258
+ ❌ **Wrong port**:
259
+ ```typescript
260
+ // WRONG
261
+ apiUrl: 'http://localhost:3000' // This is Next.js
262
+ apiUrl: 'http://localhost:3301' // Old port
263
+ ```
264
+
265
+ ❌ **Not exporting utilities**:
266
+ ```typescript
267
+ // WRONG - Forgot to export utilities
268
+ export { sdk };
269
+ // Missing TokenManager and WalletUtils!
270
+ ```
271
+
272
+ ❌ **Hardcoding values**:
273
+ ```typescript
274
+ // WRONG - Should use environment variables
275
+ apiUrl: 'http://localhost:3301', // Hardcoded
276
+ apiKey: 'some-key' // Hardcoded
277
+ ```
278
+
279
+ ## Using the SDK
280
+
281
+ After initialization, you can use it like this:
282
+
283
+ ```typescript
284
+ // In your components
285
+ import { sdk, TokenManager } from '@/lib/spaps';
286
+
287
+ // Email authentication
288
+ const auth = await sdk.auth.signInWithPassword({
289
+ email: 'test@example.com',
290
+ password: 'Test123!'
291
+ });
292
+ TokenManager.storeTokens(auth);
293
+
294
+ // Wallet authentication
295
+ const walletAuth = await sdk.auth.authenticateWallet(
296
+ address,
297
+ signatureCallback,
298
+ 'ethereum'
299
+ );
300
+
301
+ // Payments
302
+ const products = await sdk.payments.listProducts();
303
+ ```
304
+
305
+ ## Troubleshooting
306
+
307
+ ### Module Not Found
308
+
309
+ If you get "Cannot find module 'spaps-sdk'":
310
+ ```bash
311
+ npm list spaps-sdk # Check if installed
312
+ npm install spaps-sdk # Reinstall if needed
313
+ ```
314
+
315
+ ### Type Errors
316
+
317
+ If TypeScript complains about types:
318
+ 1. Restart TypeScript server in VSCode
319
+ 2. Clear Next.js cache: `rm -rf .next`
320
+ 3. Check `tsconfig.json` includes your lib folder
321
+
322
+ ### Connection Errors
323
+
324
+ If SDK can't connect to SPAPS:
325
+ ```bash
326
+ # Check SPAPS is running
327
+ curl http://localhost:3301/health
328
+
329
+ # Check your dev script
330
+ npm run dev # Should start both SPAPS and Next.js
331
+ ```
332
+
333
+ ## Next Step
334
+
335
+ When ALL todos are ✅ complete and SDK is initialized:
336
+
337
+ ```javascript
338
+ mcp__product-manager__get_agent_instructions({
339
+ category: "spaps-integration",
340
+ project: "spaps-demo",
341
+ step: 4
342
+ })
343
+ ```
344
+
345
+ ## Summary
346
+
347
+ SDK initialization is the foundation for all SPAPS features:
348
+ - **Correct package**: `spaps-sdk` (not @sweet-potato/sdk)
349
+ - **Correct port**: 3301 (not 3000, 3300, or 3456)
350
+ - **Export utilities**: TokenManager and WalletUtils
351
+ - **Use environment variables**: Don't hardcode values
@@ -0,0 +1,311 @@
1
+ # SPAPS Integration Step 4/12: Email/Password Authentication
2
+
3
+ ## Prerequisites Check
4
+
5
+ Before starting, confirm you have completed:
6
+ - ✅ Step 1: Project setup with spaps-sdk installed
7
+ - ✅ Step 2: Environment configuration with port 3301
8
+ - ✅ Step 3: SDK initialization in lib/spaps.ts
9
+
10
+ ## Required TodoWrite List
11
+
12
+ Create a TodoWrite with EXACTLY these items:
13
+
14
+ ```javascript
15
+ TodoWrite({
16
+ todos: [
17
+ { content: "Create components/auth directory structure", status: "pending", activeForm: "Creating auth directory" },
18
+ { content: "Build email/password form with shadcn/ui components", status: "pending", activeForm: "Building authentication form" },
19
+ { content: "Implement signInWithPassword with OBJECT parameter", status: "pending", activeForm: "Implementing signInWithPassword" },
20
+ { content: "Add TokenManager.storeTokens for token storage", status: "pending", activeForm: "Adding token storage" },
21
+ { content: "Setup TokenManager.autoRefreshToken", status: "pending", activeForm: "Setting up auto-refresh" },
22
+ { content: "Implement SweetPotatoAPIError handling", status: "pending", activeForm: "Implementing error handling" },
23
+ { content: "Test with test@example.com / Test123!", status: "pending", activeForm: "Testing authentication" },
24
+ { content: "Request step 5 of SPAPS integration wizard", status: "pending", activeForm: "Requesting next step" }
25
+ ]
26
+ })
27
+ ```
28
+
29
+ ## Implementation Guide
30
+
31
+ ### 1. Create Auth Component Structure
32
+ ```bash
33
+ mkdir -p components/auth
34
+ touch components/auth/email-auth-form.tsx
35
+ ```
36
+
37
+ ### 2. Import Requirements
38
+ ```typescript
39
+ // ✅ CORRECT IMPORTS
40
+ import { SweetPotatoSDK, TokenManager, SweetPotatoAPIError } from 'spaps-sdk';
41
+ import { sdk } from '@/lib/spaps';
42
+
43
+ // UI Components from shadcn/ui
44
+ import { Button } from "@/components/ui/button"
45
+ import { Input } from "@/components/ui/input"
46
+ import { Label } from "@/components/ui/label"
47
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
48
+ import { toast } from "sonner"
49
+ ```
50
+
51
+ ### 3. Authentication Implementation
52
+
53
+ ⚠️ **CRITICAL - CORRECT METHOD SIGNATURE**:
54
+
55
+ ```typescript
56
+ // ✅ CORRECT - Pass an OBJECT with email and password
57
+ const authResponse = await sdk.auth.signInWithPassword({
58
+ email: 'test@example.com',
59
+ password: 'Test123!'
60
+ });
61
+
62
+ // ❌ WRONG - DO NOT pass as separate parameters
63
+ const authResponse = await sdk.auth.signInWithPassword(email, password);
64
+ ```
65
+
66
+ ### 4. Token Management
67
+
68
+ ⚠️ **CRITICAL - CORRECT TOKEN STORAGE**:
69
+
70
+ ```typescript
71
+ // ✅ CORRECT - Pass the auth response object
72
+ TokenManager.storeTokens(authResponse);
73
+
74
+ // Then setup auto-refresh
75
+ TokenManager.autoRefreshToken(sdk);
76
+
77
+ // ❌ WRONG - DO NOT pass tokens separately
78
+ TokenManager.storeTokens(authResponse.access_token, authResponse.refresh_token);
79
+ ```
80
+
81
+ ### 5. Error Handling
82
+
83
+ Implement specific error handling:
84
+
85
+ ```typescript
86
+ try {
87
+ const auth = await sdk.auth.signInWithPassword({
88
+ email: email.trim(),
89
+ password: password
90
+ });
91
+
92
+ TokenManager.storeTokens(auth);
93
+ TokenManager.autoRefreshToken(sdk);
94
+
95
+ toast.success('Successfully authenticated!');
96
+
97
+ } catch (error) {
98
+ if (error instanceof SweetPotatoAPIError) {
99
+ switch (error.code) {
100
+ case 'INVALID_CREDENTIALS':
101
+ toast.error('Invalid email or password');
102
+ break;
103
+ case 'RATE_LIMITED':
104
+ toast.error('Too many attempts. Please wait before trying again.');
105
+ break;
106
+ case 'USER_NOT_FOUND':
107
+ toast.error('No account found with this email');
108
+ break;
109
+ default:
110
+ toast.error(error.message || 'Authentication failed');
111
+ }
112
+ } else {
113
+ toast.error('An unexpected error occurred');
114
+ }
115
+ }
116
+ ```
117
+
118
+ ### 6. Complete Component Example
119
+
120
+ ```typescript
121
+ 'use client'
122
+
123
+ import { useState } from 'react'
124
+ import { Button } from "@/components/ui/button"
125
+ import { Input } from "@/components/ui/input"
126
+ import { Label } from "@/components/ui/label"
127
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
128
+ import { toast } from "sonner"
129
+ import { sdk } from '@/lib/spaps'
130
+ import { SweetPotatoAPIError, TokenManager } from 'spaps-sdk'
131
+
132
+ export function EmailAuthForm() {
133
+ const [email, setEmail] = useState('')
134
+ const [password, setPassword] = useState('')
135
+ const [isLoading, setIsLoading] = useState(false)
136
+
137
+ const handleSubmit = async (e: React.FormEvent) => {
138
+ e.preventDefault()
139
+ setIsLoading(true)
140
+
141
+ try {
142
+ // ✅ CORRECT: Pass object with email and password
143
+ const authResponse = await sdk.auth.signInWithPassword({
144
+ email: email.trim(),
145
+ password: password
146
+ });
147
+
148
+ // ✅ CORRECT: Store tokens and setup auto-refresh
149
+ TokenManager.storeTokens(authResponse);
150
+ TokenManager.autoRefreshToken(sdk);
151
+
152
+ toast.success('Successfully authenticated!');
153
+ // Handle success (e.g., redirect, update UI)
154
+
155
+ } catch (error) {
156
+ if (error instanceof SweetPotatoAPIError) {
157
+ // Specific error handling
158
+ switch (error.code) {
159
+ case 'INVALID_CREDENTIALS':
160
+ toast.error('Invalid email or password');
161
+ break;
162
+ case 'RATE_LIMITED':
163
+ toast.error('Too many attempts. Please wait.');
164
+ break;
165
+ default:
166
+ toast.error(error.message);
167
+ }
168
+ } else {
169
+ toast.error('Authentication failed');
170
+ }
171
+ } finally {
172
+ setIsLoading(false)
173
+ }
174
+ }
175
+
176
+ // Add test credentials button
177
+ const fillTestCredentials = () => {
178
+ setEmail('test@example.com')
179
+ setPassword('Test123!')
180
+ }
181
+
182
+ return (
183
+ <Card>
184
+ <CardHeader>
185
+ <CardTitle>Sign In</CardTitle>
186
+ <CardDescription>
187
+ Enter your email and password to authenticate
188
+ </CardDescription>
189
+ </CardHeader>
190
+ <CardContent>
191
+ <form onSubmit={handleSubmit} className="space-y-4">
192
+ {/* Form fields */}
193
+ </form>
194
+ </CardContent>
195
+ </Card>
196
+ )
197
+ }
198
+ ```
199
+
200
+ ## Validation Checklist
201
+
202
+ ✅ **Method Usage**:
203
+ - Uses `signInWithPassword({ email, password })` with object parameter
204
+ - NOT using separate parameters
205
+
206
+ ✅ **Token Management**:
207
+ - Uses `TokenManager.storeTokens(authResponse)`
208
+ - Calls `TokenManager.autoRefreshToken(sdk)`
209
+ - NOT storing tokens manually in localStorage
210
+
211
+ ✅ **Error Handling**:
212
+ - Imports and uses `SweetPotatoAPIError`
213
+ - Handles `INVALID_CREDENTIALS` specifically
214
+ - Handles `RATE_LIMITED` specifically
215
+ - Shows user-friendly error messages
216
+
217
+ ✅ **UI Components**:
218
+ - Uses shadcn/ui components (Button, Input, Card, etc.)
219
+ - Includes loading states
220
+ - Shows toast notifications
221
+
222
+ ✅ **Testing**:
223
+ - Can login with test@example.com / Test123!
224
+ - Tokens are stored (check DevTools > Application > Local Storage)
225
+ - Error handling works (try wrong password)
226
+
227
+ ## Common Mistakes to Avoid
228
+
229
+ ❌ **Method signature**: `signInWithPassword(email, password)` - MUST pass object
230
+ ❌ **Token storage**: Using localStorage directly instead of TokenManager
231
+ ❌ **Missing imports**: Not importing SweetPotatoAPIError
232
+ ❌ **Generic errors**: Not handling specific error codes
233
+ ❌ **No loading state**: Form doesn't show loading indicator
234
+ ❌ **No auto-refresh**: Forgetting to call autoRefreshToken
235
+
236
+ ## Server Contract Note: TOTP MFA Challenge on Login
237
+
238
+ If the user has activated TOTP MFA on their SPAPS account, `POST /api/auth/login`
239
+ returns an MFA challenge payload **instead of tokens**:
240
+
241
+ ```json
242
+ { "mfa_required": true, "challenge_id": "...", "challenge": "...", "expires_at": "...", "methods": ["totp", "recovery_code"] }
243
+ ```
244
+
245
+ Handle this branch before assuming tokens exist: echo `challenge_id` +
246
+ `challenge` to `POST /api/auth/mfa/verify` together with the user's 6-digit
247
+ TOTP code (or a single-use recovery code) to receive the standard token
248
+ payload. Challenges expire after 300 seconds and allow at most 5 attempts.
249
+ Accounts that never enrolled in MFA are unaffected — login returns tokens
250
+ directly as shown above. MFA enforcement currently covers email/password
251
+ login only (not magic-link, wallet, OIDC, WebAuthn-assertion, or SMS sign-in).
252
+
253
+ ## Other SPAPS Login Methods (server API)
254
+
255
+ Beyond email/password (this step), wallet sign-in (step 5), and magic link
256
+ (step 6), the SPAPS server also supports — via direct API calls; SDK helper
257
+ coverage may lag:
258
+
259
+ - **OIDC social sign-in** — `POST /api/auth/oidc/nonce` then
260
+ `POST /api/auth/oidc/sign-in` with a provider ID token (Google, Apple,
261
+ GitHub-issued OIDC). Pass the RAW nonce to the provider (hashed-nonce
262
+ flows are not matched). Requires the SPAPS operator to seed an
263
+ `auth_provider_configs` row for your application.
264
+ - **WebAuthn passkeys** — `POST /api/auth/webauthn/register/{options,verify}`
265
+ (authenticated) and `POST /api/auth/webauthn/assertion/{options,verify}`
266
+ (sign-in).
267
+ - **SMS OTP** — `POST /api/auth/sms/request` then `POST /api/auth/sms/verify`.
268
+
269
+ All of these return the same token payload shape as `/api/auth/login`, so
270
+ `TokenManager.storeTokens` works unchanged.
271
+
272
+ ## Testing Requirements
273
+
274
+ 1. **Successful Login**:
275
+ - Email: `test@example.com`
276
+ - Password: `Test123!`
277
+ - Should see success toast
278
+ - Tokens stored in browser
279
+
280
+ 2. **Failed Login**:
281
+ - Wrong password: Should show "Invalid credentials"
282
+ - Rate limiting: After 5 attempts, should show rate limit message
283
+
284
+ 3. **Token Verification**:
285
+ ```javascript
286
+ // In browser console:
287
+ const token = TokenManager.getAccessToken();
288
+ console.log('Token exists:', !!token);
289
+ ```
290
+
291
+ ## Next Step
292
+
293
+ When ALL todos are ✅ complete and tests pass:
294
+
295
+ ```javascript
296
+ mcp__product-manager__get_agent_instructions({
297
+ category: "spaps-integration",
298
+ project: "spaps-demo",
299
+ step: 5
300
+ })
301
+ ```
302
+
303
+ ## Troubleshooting
304
+
305
+ If authentication fails:
306
+ 1. Check SPAPS is running on port 3301: `curl http://localhost:3301/health`
307
+ 2. Verify SDK initialization in lib/spaps.ts
308
+ 3. Check browser console for specific errors
309
+ 4. Ensure you're using the object parameter format
310
+
311
+ Remember: **The parameter format is critical!** Most failures come from using separate parameters instead of an object.