MCP (Model Context Protocol) User Guide β
This guide explains how to configure and use the Model Context Protocol (MCP) integration with the NetApp Connector, enabling AI assistants like ChatGPT Enterprise and Anthropic Claude to search and retrieve files from your file shares with proper access control.
Table of Contents β
- Overview
- Architecture
- Prerequisites
- Configuration
- Claude Desktop Setup
- Available Tools
- Security & Access Control
- Rate Limiting
- Troubleshooting
- Environment Variables Reference
Overview β
The MCP integration allows AI assistants to securely search and retrieve content from your NetApp file shares. Key features include:
- π ACL-Based Access Control: Users can only access files they have permission to view based on SMB ACLs resolved to Microsoft Entra IDs
- π Full-Text Search: Search file content using natural language queries
- π Content Windowing: Navigate large documents in chunks that fit AI context windows
- β‘ Rate Limiting: Per-user rate limits prevent abuse and ensure fair usage
- π OAuth 2.0 Authentication: Secure authentication via Microsoft Entra ID
How It Works β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β User asks Claude a question β
β "Find the Q4 financial reports" β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Claude Desktop β
β Uses MCP tools to search files β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β MCP Protocol (HTTP + OAuth)
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β NetApp Connector MCP Server β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββ β
β β OAuth β β ACL Filter β β Rate Limiterβ β Content Windowing β β
β β Validation β β (per-user) β β (per-user) β β (large documents) β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β Internal API calls
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β NetApp Connector Database β
β (File metadata, content, ACLs, search indexes) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββArchitecture β
Component Diagram β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AI AGENT LAYER β
β ββββββββββββββββββ ββββββββββββββββββ ββββββββββββββββββ β
β β Claude Desktop β β Windsurf IDE β β Custom Agent β β
β βββββββββ¬βββββββββ βββββββββ¬βββββββββ βββββββββ¬βββββββββ β
β β β β β
β βββββββββββββββββββββΌββββββββββββββββββββ β
β β β
ββββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββ
β MCP Protocol
β (HTTP POST /mcp)
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MCP SERVER LAYER β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β HTTP Transport (FastAPI Router) β β
β β POST /mcp endpoint β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββ β
β βΌ βΌ βΌ β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β OAuth β β ACL Filter β β Rate β β
β β Validation β β β β Limiter β β
β β β β - User ID β β β β
β β - Entra ID β β - Groups β β - Per-tool β β
β β - JWT β β - Share ACL β β - Per-user β β
β β - Groups β β Override β β - Bytes β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β MCP TOOLS β β
β β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β β
β β β search_files β β full_text_ β β get_file_ β β list_shares β β β
β β β β β search β β content β β β β β
β β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β β
β β ββββββββββββββββ β β
β β β search_ β β β
β β β entities β β β
β β ββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
β Internal HTTP
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β NETAPP CONNECTOR API β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββ β
β β GET /files β β POST /searchβ β GET /shares β β GET /ner/entities β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββData Flow for File Access β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β FILE ACCESS FLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
User Request MCP Server Response
β β β
β 1. "Get quarterly report" β β
βββββββββββββββββββββββββββββββΊβ β
β β β
β βββββββββββ΄ββββββββββ β
β β 2. Validate OAuth β β
β β Bearer Token β β
β βββββββββββ¬ββββββββββ β
β β β
β βββββββββββ΄ββββββββββ β
β β 3. Extract User β β
β β Object ID & β β
β β Group Members β β
β βββββββββββ¬ββββββββββ β
β β β
β βββββββββββ΄ββββββββββ β
β β 4. Search Files β β
β β in Database β β
β βββββββββββ¬ββββββββββ β
β β β
β βββββββββββ΄ββββββββββ β
β β 5. ACL Filter: β β
β β Check each fileβ β
β β resolved_ β β
β β principals β β
β βββββββββββ¬ββββββββββ β
β β β
β βββββββββββ΄ββββββββββ β
β β 6. Return only β β
β β accessible β β
β β files β β
β βββββββββββ¬ββββββββββ β
β β β
ββββββββββββββββββββββββββββββββ€ β
β 7. Filtered results β βPrerequisites β
Before configuring MCP, ensure you have:
- NetApp Connector Running: The connector API must be accessible (default:
http://localhost:8080) - Microsoft Entra ID App Registration: Required for OAuth authentication
- Indexed File Shares: At least one share must be configured and crawled
- ACL Resolution Enabled: Files should have
resolved_principalsfor proper access control
Microsoft Entra ID Requirements β
Your Entra ID app registration needs:
| Permission | Type | Purpose |
|---|---|---|
User.Read | Delegated | Read user profile |
openid | Delegated | OpenID Connect sign-in |
profile | Delegated | Read user's basic profile |
email | Delegated | Read user's email address |
Configuration β
Step 1: Configure Environment Variables β
Add these to your .env file or container environment:
# OAuth Configuration (Required for MCP)
MCP_OAUTH_ENABLED=true
MCP_OAUTH_TENANT_ID=your-tenant-id # Microsoft Entra tenant ID
MCP_OAUTH_CLIENT_ID=your-client-id # App registration client ID
MCP_OAUTH_CLIENT_SECRET=your-client-secret # App registration secret
# Optional: Rate Limiting Configuration
MCP_RATE_LIMIT_SEARCH=30 # search_files requests per minute
MCP_RATE_LIMIT_FULL_TEXT=20 # full_text_search requests per minute
MCP_RATE_LIMIT_CONTENT=60 # get_file_content requests per minute
MCP_RATE_LIMIT_SHARES=10 # list_shares requests per minute
MCP_RATE_LIMIT_ENTITIES=20 # search_entities requests per minute
MCP_RATE_LIMIT_TOTAL=100 # Total requests per minute per user
MCP_RATE_LIMIT_BYTES=10485760 # Content bytes per minute (10MB)
# Optional: Content Windowing
MCP_DEFAULT_WINDOW_SIZE=50000 # Default content window (50KB)
MCP_MAX_WINDOW_SIZE=100000 # Maximum content window (100KB)
# Optional: Default ACL Mode (when no resolved_principals)
MCP_DEFAULT_ACL_MODE=deny # "deny" (secure) or "allow"Step 2: Verify MCP Endpoint β
Once configured, verify the MCP endpoint is available:
# Check OAuth metadata endpoint
curl http://localhost:8080/.well-known/oauth-protected-resource
# Expected response:
{
"resource": "http://localhost:8080/mcp",
"authorization_servers": ["http://localhost:8080"],
"scopes_supported": ["openid", "profile", "email", "offline_access"],
"bearer_methods_supported": ["header"]
}Claude Desktop Setup β
Option A: HTTP Transport with Automatic OAuth (Recommended) β
This method allows Claude Desktop to handle OAuth automatically. Edit your Claude Desktop configuration file:
Location:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/claude/claude_desktop_config.json
Configuration:
{
"mcpServers": {
"netapp-files": {
"url": "http://localhost:8080/mcp",
"oauth": {
"client_id": "your-client-id",
"client_secret": "your-client-secret",
"authorization_url": "http://localhost:8080/authorize",
"token_url": "http://localhost:8080/token",
"scopes": ["openid", "profile", "email"]
}
}
}
}How it works:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β AUTOMATIC OAUTH FLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Claude Desktop NetApp Connector Microsoft Entra
β β β
β 1. First MCP request β β
βββββββββββββββββββββββββββββΊβ β
β β β
β 2. 401 + WWW-Authenticate β β
ββββββββββββββββββββββββββββββ€ β
β β β
β 3. Open browser for login β β
ββββββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββΊβ
β β β
β β 4. User signs in β
β βββββββββββββββββββββββββββββββ€
β β β
β 5. Receive auth code β β
ββββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββ€
β β β
β 6. Exchange for token β β
βββββββββββββββββββββββββββββΊβ β
β β β
β 7. Access token β β
ββββββββββββββββββββββββββββββ€ β
β β β
β 8. MCP request + Bearer β β
βββββββββββββββββββββββββββββΊβ β
β β β
β 9. Results (ACL filtered) β β
ββββββββββββββββββββββββββββββ€ βOption B: stdio Transport with Manual Token β
For development or when HTTP transport isn't available:
{
"mcpServers": {
"netapp-files": {
"command": "python",
"args": ["-m", "app.mcp"],
"cwd": "/path/to/netapp-copilot-connector-gen-2",
"env": {
"NETAPP_API_URL": "http://localhost:8080",
"MCP_OAUTH_ENABLED": "true",
"MCP_OAUTH_TENANT_ID": "your-tenant-id",
"MCP_OAUTH_CLIENT_ID": "your-client-id",
"MCP_OAUTH_CLIENT_SECRET": "your-client-secret",
"MCP_OAUTH_TOKEN": "your-user-oauth-token"
}
}
}
}Note: With Option B, you must manually obtain and update the OAuth token.
Getting a Manual OAuth Token β
If using stdio transport, obtain a token using one of these methods:
Method 1: Browser Login β
- Visit
http://localhost:8080/auth/login - Sign in with your Microsoft account
- Copy the access token from the success page
Method 2: Device Code Flow β
# 1. Initiate device code flow
curl -X POST "http://localhost:8080/auth/device"
# Response:
# {
# "user_code": "ABCD1234",
# "verification_uri": "https://microsoft.com/devicelogin",
# "device_code": "..."
# }
# 2. Visit the URL and enter the code
# 3. Poll for the token
curl -X POST "http://localhost:8080/auth/device/poll?device_code=YOUR_DEVICE_CODE"Method 3: Azure CLI β
az login
az account get-access-token --resource api://your-client-id --query accessToken -o tsvAvailable Tools β
The MCP server exposes five tools for AI agents:
1. search_files β
Search for files by name, type, date, or size across all accessible shares.
Parameters:
| Parameter | Type | Description |
|---|---|---|
query | string | Text to search in filename (case-insensitive) |
file_type | string | Filter by extension: pdf, docx, xlsx, etc. |
path | string | Filter by path pattern (e.g., /reports/) |
modified_after | string | ISO datetime - files modified after this date |
modified_before | string | ISO datetime - files modified before this date |
size_min | integer | Minimum file size in bytes |
size_max | integer | Maximum file size in bytes |
limit | integer | Max results (default: 20, max: 100) |
Example Usage:
"Find all PDF files modified in the last month"
β search_files(file_type="pdf", modified_after="2024-11-01")2. full_text_search β
Search file content using natural language queries with boolean operators.
Parameters:
| Parameter | Type | Description |
|---|---|---|
query | string | Required. Search query with optional operators |
file_types | array | Filter by file types: ["pdf", "docx"] |
limit | integer | Max results (default: 20, max: 100) |
Query Syntax:
- Simple:
quarterly report - AND:
budget AND 2024 - OR:
invoice OR receipt - Phrase:
"project alpha" - Exclude:
report -draft
Example Usage:
"Search for documents mentioning Project Alpha"
β full_text_search(query="\"Project Alpha\"")3. get_file_content β
Retrieve extracted text content from a file with windowing for large documents.
Parameters:
| Parameter | Type | Description |
|---|---|---|
file_id | string | Required. File ID from search results |
share_id | string | Share ID (optional, improves performance) |
window_start | integer | Character offset to start from (default: 0) |
window_size | integer | Characters to return (default: 50000, max: 100000) |
include_metadata | boolean | Include file metadata (default: true) |
Response includes navigation hints:
{
"file_id": "abc123",
"filename": "annual_report.pdf",
"content": "... extracted text ...",
"window": {
"start": 0,
"size": 50000,
"total_length": 250000,
"has_more": true,
"next_start": 50000,
"progress_percent": 20
}
}Scrolling through large documents:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β CONTENT WINDOWING β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Document (250KB total)
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β Window 1: 0-50KB Window 2: 50-100KB Window 3: 100-150KB β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β Introduction β β β Chapter 1 β β β Chapter 2 β ... β
β β Executive β β Analysis β β Results β β
β β Summary β β β β β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Request 1: get_file_content(file_id="abc", window_start=0)
Request 2: get_file_content(file_id="abc", window_start=50000)
Request 3: get_file_content(file_id="abc", window_start=100000)4. list_shares β
List available file shares in the system.
Parameters: None
Response:
{
"shares": [
{
"id": "share-uuid",
"name": "Finance",
"path": "\\\\server\\finance",
"status": "READY",
"file_count": 1250
}
]
}5. search_entities β
Find files containing specific named entities (people, organizations, etc.) extracted via NER.
Parameters:
| Parameter | Type | Description |
|---|---|---|
entity_value | string | Required. Entity to search for |
entity_type | string | Type filter: person, organization, location, date, money, email, phone |
limit | integer | Max results (default: 20, max: 100) |
Example Usage:
"Find documents mentioning Acme Corporation"
β search_entities(entity_value="Acme Corporation", entity_type="organization")Security & Access Control β
ACL Filtering Flow β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ACL ACCESS DECISION FLOW β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββ
β File Request β
ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββββββββββ
β File has resolved_ β
β principals? β
ββββββββββββββ¬βββββββββββββ
β
βββββββββββββββββββ΄ββββββββββββββββββ
β YES β NO
βΌ βΌ
βββββββββββββββββββββββ βββββββββββββββββββββββ
β User Object ID in β β Share has β
β resolved_principals?β β acl_override_mode? β
ββββββββββββ¬βββββββββββ ββββββββββββ¬βββββββββββ
β β
ββββββββββββ΄βββββββββββ ββββββββββββ΄βββββββββββ
β YES β NO β β YES β NO β
βΌ βΌ β βΌ βΌ
ββββββββββ βββββββββββββ β βββββββββββββ ββββββββββ
β ALLOW β β User in β β β Check β β DENY β
β β β group in β β β override β β β
ββββββββββ β resolved_ β β β rules β ββββββββββ
β principalsβ β βββββββ¬ββββββ
βββββββ¬ββββββ β β
β β ββββββββ΄βββββββ
ββββββββββ΄ββββββββ β β
β YES β NO β βΌ βΌ
βΌ βΌ β "everyone" "specified"
ββββββββββ βββββββββββ ββββββββββ βββββββββββββ
β ALLOW β β DENY ββ β ALLOW β β User in β
ββββββββββ βββββββββββ ββββββββββ β specified β
β β principalsβ
β βββββββ¬ββββββ
β β
β ββββββββ΄βββββββ
β β YES β NO β
β βΌ βΌ
β ββββββββββ ββββββββββ
β β ALLOW β β DENY β
β ββββββββββ ββββββββββShare-Level ACL Override β
When files don't have resolved ACL principals, you can configure share-level fallback:
{
"rules": {
"acl_override_mode": "everyone"
}
}Options:
"everyone"- All authenticated users can access files without resolved ACLs"specified"- Only specified users/groups can access:
{
"rules": {
"acl_override_mode": "specified",
"acl_override_principals": [
{ "type": "group", "id": "group-object-id" },
{ "type": "user", "id": "user-object-id" }
]
}
}Security Best Practices β
- Keep
MCP_DEFAULT_ACL_MODE=deny- This ensures files without resolved ACLs are not accessible - Use HTTPS in production - Configure SSL/TLS for the connector API
- Rotate client secrets regularly - Update your Entra ID app registration secrets
- Monitor MCP operations - All MCP tool calls are logged to the operations log
- Configure appropriate rate limits - Prevent abuse with per-user limits
Rate Limiting β
Rate limits protect the system from abuse and ensure fair usage across users.
Default Limits (per minute per user) β
| Limit Type | Default | Environment Variable |
|---|---|---|
search_files | 30 | MCP_RATE_LIMIT_SEARCH |
full_text_search | 20 | MCP_RATE_LIMIT_FULL_TEXT |
get_file_content | 60 | MCP_RATE_LIMIT_CONTENT |
list_shares | 10 | MCP_RATE_LIMIT_SHARES |
search_entities | 20 | MCP_RATE_LIMIT_ENTITIES |
| Total requests | 100 | MCP_RATE_LIMIT_TOTAL |
| Content bytes | 10MB | MCP_RATE_LIMIT_BYTES |
Rate Limit Response β
When rate limited, tools return:
{
"error": "rate_limited",
"message": "Rate limit exceeded for search_files",
"retry_after": 45,
"rate_limit": {
"allowed": false,
"remaining": 0,
"limit": 30,
"reset_at": 1702732800.0
}
}Troubleshooting β
Common Issues β
1. "OAuth provider not configured" β
Cause: Missing OAuth environment variables
Solution: Ensure these are set:
MCP_OAUTH_ENABLED=true
MCP_OAUTH_TENANT_ID=your-tenant-id
MCP_OAUTH_CLIENT_ID=your-client-id
MCP_OAUTH_CLIENT_SECRET=your-client-secret2. "Token validation failed" β
Cause: Invalid or expired OAuth token
Solutions:
- Refresh your OAuth token
- Check that the token audience matches your app registration
- Verify the token hasn't expired
3. "Access denied" for files you should have access to β
Cause: ACL resolution issues
Solutions:
- Verify the file has
resolved_principalsin the database - Check that your Entra Object ID matches a principal
- Verify your group memberships are being fetched correctly
- Consider configuring
acl_override_modeon the share
4. "Rate limit exceeded" β
Cause: Too many requests in a short period
Solutions:
- Wait for the
retry_afterperiod - Reduce request frequency
- Increase rate limits via environment variables
5. Files not appearing in search results β
Causes:
- Files haven't been crawled yet
- Files don't match your ACL permissions
- Search filters are too restrictive
Solutions:
- Verify the share has been crawled (check share status)
- Check file ACLs and your permissions
- Broaden search parameters
Viewing MCP Logs β
MCP operations are logged to the connector's operations log:
# View recent MCP operations
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8080/operations?operation_type=MCP_SEARCH_FILES&limit=10"Log entries include:
- Tool name and arguments
- User identity (Object ID, email)
- Operation status (SUCCESS/ERROR)
- Result counts
Environment Variables Reference β
OAuth Configuration β
| Variable | Required | Default | Description |
|---|---|---|---|
MCP_OAUTH_ENABLED | Yes | false | Enable OAuth authentication |
MCP_OAUTH_TENANT_ID | Yes | - | Microsoft Entra tenant ID |
MCP_OAUTH_CLIENT_ID | Yes | - | App registration client ID |
MCP_OAUTH_CLIENT_SECRET | Yes | - | App registration client secret |
MCP_OAUTH_TOKEN | No | - | Pre-configured OAuth token (stdio mode) |
Rate Limiting β
| Variable | Required | Default | Description |
|---|---|---|---|
MCP_RATE_LIMIT_SEARCH | No | 30 | search_files requests/min |
MCP_RATE_LIMIT_FULL_TEXT | No | 20 | full_text_search requests/min |
MCP_RATE_LIMIT_CONTENT | No | 60 | get_file_content requests/min |
MCP_RATE_LIMIT_SHARES | No | 10 | list_shares requests/min |
MCP_RATE_LIMIT_ENTITIES | No | 20 | search_entities requests/min |
MCP_RATE_LIMIT_TOTAL | No | 100 | Total requests/min per user |
MCP_RATE_LIMIT_BYTES | No | 10485760 | Content bytes/min (10MB) |
Content Windowing β
| Variable | Required | Default | Description |
|---|---|---|---|
MCP_DEFAULT_WINDOW_SIZE | No | 50000 | Default window size (chars) |
MCP_MAX_WINDOW_SIZE | No | 100000 | Maximum window size (chars) |
Access Control β
| Variable | Required | Default | Description |
|---|---|---|---|
MCP_DEFAULT_ACL_MODE | No | deny | Default ACL mode when no resolved_principals |
Server Configuration β
| Variable | Required | Default | Description |
|---|---|---|---|
NETAPP_API_URL | No | http://localhost:8080 | NetApp Connector API URL |
MCP_LOG_LEVEL | No | INFO | Logging level |
Additional Resources β
- MCP Protocol Specification
- Microsoft Entra ID Documentation
- ChatGPT Enterprise Developer Mode Guide
- Claude Desktop MCP Guide
- NetApp Connector API Documentation
Last updated: January 2026