Skip to content

Commit 3c2e34e

Browse files
authored
Merge pull request #15 from SkyflowFoundry/jstjoe/anon-mode
Add anonymous mode for unauthenticated requests
2 parents 06fc87f + 6f9c6c5 commit 3c2e34e

11 files changed

Lines changed: 1087 additions & 28 deletions

File tree

‎.env.sample‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,14 @@ ACCOUNT_ID=""
99

1010
# Note: SKYFLOW_API_KEY and REQUIRED_BEARER_TOKEN are no longer used
1111
# The bearer token is now passed through from the client to Skyflow
12+
13+
# Anonymous Mode Configuration
14+
# When set, allows unauthenticated requests with limited functionality
15+
# Only the 'dehydrate' tool works in anonymous mode (with ENTITY_UNIQUE_COUNTER tokens)
16+
ANON_MODE_API_KEY="" # Skyflow API key for demo vault
17+
ANON_MODE_VAULT_ID="" # Demo vault ID
18+
ANON_MODE_VAULT_URL="" # Demo vault URL (e.g., https://demo.vault.skyflowapis.com)
19+
20+
# Anonymous Mode Rate Limiting
21+
ANON_MODE_RATE_LIMIT_REQUESTS=10 # Max requests per window (default: 10)
22+
ANON_MODE_RATE_LIMIT_WINDOW_MS=60000 # Window duration in milliseconds (default: 1 minute)

‎.vercel/project.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"projectId":"prj_O92h6fOjuzj1Csx68wrJSEEtCS08","orgId":"team_EHvZvBIOBvSYYsZJZEQ2rcnO","projectName":"sky-mcp-streamable"}
1+
{"projectId":"prj_O92h6fOjuzj1Csx68wrJSEEtCS08","orgId":"team_w0Tg32Q0GT1KuUyTBaZpLg8G","projectName":"sky-mcp-streamable"}

‎CLAUDE.md‎

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,10 @@ curl -X POST "http://localhost:3000/mcp?vaultId={vault_id}&vaultUrl={vault_url}"
7676
### Tool Implementations
7777

7878
**dehydrate tool**
79-
- Detects and replaces sensitive information with vault tokens
79+
- Detects and replaces sensitive information with tokens
8080
- Returns processed text with word/character counts
81-
- Uses `TokenFormat` with `VAULT_TOKEN` type
81+
- Uses `TokenFormat` with `VAULT_TOKEN` type in authenticated mode, `ENTITY_UNIQUE_COUNTER` in anonymous mode
82+
- In anonymous mode, adds `anonymousMode: true` and a note to the response
8283
- Has commented-out support for custom regex allow/restrict lists
8384

8485
**rehydrate tool**
@@ -139,6 +140,32 @@ Fallback method (API key via query parameter):
139140
https://your-server.com/mcp?vaultId={vault_id}&vaultUrl={vault_url}&accountId={account_id}&workspaceId={workspace_id}&apiKey={your_skyflow_api_key}
140141
```
141142

143+
## Anonymous Mode
144+
145+
When no credentials are provided in a request, the server can operate in "anonymous mode" if the following environment variables are configured:
146+
147+
**Environment Variables for Anonymous Mode**:
148+
- `ANON_MODE_API_KEY`: Skyflow API key for demo vault
149+
- `ANON_MODE_VAULT_ID`: Demo vault identifier
150+
- `ANON_MODE_VAULT_URL`: Demo vault URL (e.g., `https://demo.vault.skyflowapis.com`)
151+
- `ANON_MODE_RATE_LIMIT_REQUESTS`: Max requests per window (default: 10)
152+
- `ANON_MODE_RATE_LIMIT_WINDOW_MS`: Window duration in milliseconds (default: 60000)
153+
154+
**Tool Behavior in Anonymous Mode**:
155+
156+
| Tool | Anonymous Mode | Authenticated Mode |
157+
|------|---------------|-------------------|
158+
| `dehydrate` | Works with `ENTITY_UNIQUE_COUNTER` tokens | Works with `VAULT_TOKEN` tokens |
159+
| `rehydrate` | Returns error with setup instructions | Works normally |
160+
| `dehydrate_file` | Returns error with setup instructions | Works normally |
161+
162+
**Token Format Difference**:
163+
- **Anonymous mode**: Uses `TokenType.ENTITY_UNIQUE_COUNTER` - generates tokens like `[EMAIL_ADDRESS_1]`, `[SSN_2]`. Data is NOT persisted to vault.
164+
- **Authenticated mode**: Uses `TokenType.VAULT_TOKEN` - generates tokens like `[EMAIL_ADDRESS_abc123xyz]` that are stored in the vault and can be rehydrated.
165+
166+
**Rate Limiting**:
167+
Anonymous mode requests are rate-limited based on client IP address. When the limit is exceeded, a 429 response is returned with `X-RateLimit-*` headers indicating when the limit resets.
168+
142169
## Port Configuration
143170

144171
- **3000**: MCP server (configurable via `PORT` env var)
@@ -212,9 +239,12 @@ All tools return both text and structured content:
212239
return {
213240
content: [{ type: "text", text: JSON.stringify(output) }],
214241
structuredContent: output,
242+
isError: true, // Optional: set to true when tool returns an error condition
215243
};
216244
```
217245

246+
The `isError` property is set to `true` when a tool returns an error condition (e.g., when `rehydrate` or `dehydrate_file` are called in anonymous mode, or when Skyflow API returns an error). This allows MCP clients to distinguish between successful responses and error responses.
247+
218248
## Dependencies
219249

220250
- `@modelcontextprotocol/sdk`: Official MCP TypeScript SDK (v1.19.1+)
@@ -228,8 +258,10 @@ return {
228258

229259
1. **Don't reuse transport or Skyflow instances** - Always create new ones per request
230260
2. **File size limits** - Base64 encoding adds ~33% overhead; 5MB limit means ~3.75MB original files
231-
3. **Credentials required** - All `/mcp` requests must include either valid `Authorization: Bearer <token>` header with a Skyflow bearer token OR `apiKey` query parameter with a Skyflow API key
232-
4. **Query parameters required** - `vaultId` and `vaultUrl` must be provided (via query params or env vars)
261+
3. **Credentials or anonymous mode required** - All `/mcp` requests must include valid credentials OR anonymous mode must be configured via `ANON_MODE_*` environment variables
262+
4. **Query parameters required** - `vaultId` and `vaultUrl` must be provided (via query params or env vars) - unless using anonymous mode
233263
5. **Vault configuration** - `clusterId` is automatically extracted from `vaultUrl`, don't set it separately
234264
6. **Entity type validation** - Use exact strings from `ENTITY_MAP` keys, not the enum values
235-
7. **AsyncLocalStorage context** - Tools must run within the request context to access Skyflow instance via `getCurrentSkyflow()`
265+
7. **AsyncLocalStorage context** - Tools must run within the request context to access Skyflow instance via `getCurrentSkyflow()` and `isAnonymousMode()`
266+
8. **Anonymous mode limitations** - Only the `dehydrate` tool works in anonymous mode; `rehydrate` and `dehydrate_file` return errors with setup instructions
267+
9. **Keep schemas in sync** - When modifying tool inputs or return values, always update the corresponding `inputSchema` and `outputSchema` in the tool registration. The schemas must match the actual implementation.

‎README.md‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,54 @@ Create a `.env.local` file with optional fallback values:
155155

156156
**Note**: `SKYFLOW_API_KEY` and `REQUIRED_BEARER_TOKEN` are no longer used. The bearer token is now passed through from the client to Skyflow.
157157

158+
## Anonymous Mode (Try Before You Buy)
159+
160+
You can try the dehydrate tool without configuring Skyflow credentials. When no credentials are provided and anonymous mode is enabled on the server, limited functionality is available.
161+
162+
### Quick Start (Anonymous)
163+
164+
```bash
165+
# No credentials needed!
166+
curl -X POST "https://pii-mcp.dev/mcp" \
167+
-H "Content-Type: application/json" \
168+
-H "Accept: application/json, text/event-stream" \
169+
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"dehydrate","arguments":{"inputString":"My email is john@example.com and my SSN is 123-45-6789"}},"id":1}'
170+
```
171+
172+
### Limitations in Anonymous Mode
173+
174+
- **Only `dehydrate` tool available** - `rehydrate` and `dehydrate_file` return helpful errors
175+
- **Tokens use entity counters** - e.g., `[EMAIL_ADDRESS_1]`, `[SSN_2]` instead of vault tokens
176+
- **Data is NOT persisted** - tokens cannot be rehydrated later
177+
- **Rate limited** - 10 requests per minute per IP (configurable by server operator)
178+
179+
### Claude Desktop (Anonymous)
180+
181+
To use anonymous mode with Claude Desktop:
182+
183+
```json
184+
{
185+
"mcpServers": {
186+
"skyflow-pii-demo": {
187+
"command": "npx",
188+
"args": ["mcp-remote", "https://pii-mcp.dev/mcp"]
189+
}
190+
}
191+
}
192+
```
193+
194+
To unlock full functionality (rehydrate, file processing, persistent vault tokens), configure your Skyflow credentials as shown in the sections above.
195+
196+
### Server Configuration for Anonymous Mode
197+
198+
Server operators can enable anonymous mode by setting these environment variables:
199+
200+
- `ANON_MODE_API_KEY`: Skyflow API key for demo vault
201+
- `ANON_MODE_VAULT_ID`: Demo vault identifier
202+
- `ANON_MODE_VAULT_URL`: Demo vault URL
203+
- `ANON_MODE_RATE_LIMIT_REQUESTS`: Max requests per window (default: 10)
204+
- `ANON_MODE_RATE_LIMIT_WINDOW_MS`: Window duration in ms (default: 60000)
205+
158206
## Testing
159207

160208
**Note**: All requests require authentication and configuration. Replace placeholders with your actual values:

‎package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
"devDependencies": {
2525
"@types/express": "^5.0.3",
2626
"@types/node": "^24.10.1",
27+
"@vitest/coverage-v8": "^4.0.18",
2728
"typescript": "^5.9.3",
2829
"vitest": "^4.0.8"
2930
}

0 commit comments

Comments
 (0)