Skip to content

Commit e79fc48

Browse files
authored
Merge pull request #1 from VectifyAI/feat/oauth-authentication
feat: implement OAuth authentication
2 parents 6cc2a45 + 8bfb649 commit e79fc48

File tree

15 files changed

+579
-189
lines changed

15 files changed

+579
-189
lines changed

README.md

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,32 +20,28 @@ PageIndex is a revolutionary document processing system that uses **reasoning-ba
2020
- **Local PDF Processing**: Upload local PDF files directly without manual uploads
2121
- **URL Support**: Process documents from URLs
2222
- **Full PageIndex Integration**: Access all PageIndex capabilities (OCR, tree generation, reasoning-based retrieval)
23-
- **Secure Authentication**: API key authentication with PageIndex platform
23+
- **Secure OAuth Authentication**: OAuth 2.1 with PKCE and automatic token refresh
2424
- **TypeScript**: Full type safety with MCP SDK
2525
- **Desktop Extension (DXT)**: One-click installation for Claude Desktop with secure configuration
2626

2727
## Usage
2828

2929
### Getting Started
3030

31-
First, you'll need to create an API key:
32-
33-
1. Visit https://dash.pageindex.ai/api-keys
34-
2. Create a new API key for your application
35-
3. Copy the API key for use in the configuration below
31+
The PageIndex MCP server uses OAuth 2.1 authentication for secure access. When you first run the server, it will guide you through the authentication process by opening your browser to authorize the application.
3632

3733
### For Claude Desktop (Recommended)
3834

3935
**One-Click Installation with Desktop Extension (DXT):**
4036

4137
1. Download the latest `.dxt` file from [Releases](https://github.com/VectifyAI/pageindex-mcp/releases)
4238
2. Double-click the `.dxt` file to install automatically in Claude Desktop
43-
3. Enter your PageIndex API key in the simple configuration interface
39+
3. The OAuth authentication will be handled automatically when you first use the extension
4440

4541
**Benefits of DXT Installation:**
4642

4743
- **No technical setup** - just download and double-click
48-
- **Secure configuration** - API keys stored securely by Claude Desktop
44+
- **Secure OAuth authentication** - handled automatically through your browser
4945
- **Automatic updates** - extensions update seamlessly
5046
- **Full local PDF support** - upload and process PDFs directly from your computer
5147

@@ -64,34 +60,57 @@ Add to your MCP configuration:
6460
"mcpServers": {
6561
"pageindex": {
6662
"command": "npx",
67-
"args": ["-y", "pageindex-mcp"],
68-
"env": {
69-
"PAGEINDEX_API_KEY": "<YOUR_PAGEINDEX_API_KEY>"
70-
}
63+
"args": ["-y", "pageindex-mcp"]
7164
}
7265
}
7366
}
7467
```
7568

76-
#### Option 2: Remote MCP Server
69+
**Authentication Process:**
70+
1. When you first connect, the server will automatically open your browser for OAuth authentication
71+
2. Log in to your PageIndex account and authorize the application
72+
3. The authentication tokens are securely stored locally and automatically refreshed
73+
4. Subsequent connections will use the stored credentials automatically
74+
75+
> **Note**: This local server provides full PDF upload capabilities and handles all authentication automatically.
7776
78-
Alternatively, connect directly to PageIndex without this wrapper:
77+
#### Option 2: Direct Connection to PageIndex
78+
79+
Connect directly to the PageIndex OAuth-enabled MCP server:
7980

8081
```json
8182
{
8283
"mcpServers": {
8384
"pageindex": {
8485
"type": "http",
85-
"url": "https://dash.pageindex.ai/api/mcp",
86-
"headers": {
87-
"Authorization": "Bearer <YOUR_PAGEINDEX_API_KEY>"
88-
}
86+
"url": "https://mcp.pageindex.ai"
87+
}
88+
}
89+
}
90+
```
91+
92+
**Authentication Process:**
93+
1. The MCP client will automatically handle the OAuth flow
94+
2. You'll be redirected to authorize the application in your browser
95+
3. Authentication tokens are managed by the MCP client
96+
4. Automatic token refresh is handled by the server
97+
98+
**For clients that don't support HTTP MCP servers:**
99+
100+
If your MCP client doesn't support HTTP servers directly, you can use [mcp-remote](https://github.com/geelen/mcp-remote) as a bridge:
101+
102+
```json
103+
{
104+
"mcpServers": {
105+
"pageindex": {
106+
"command": "npx",
107+
"args": ["-y", "mcp-remote", "https://mcp.pageindex.ai"]
89108
}
90109
}
91110
}
92111
```
93112

94-
> **Note**: Option 1 provides local PDF upload capabilities, while Option 2 connects directly to PageIndex but requires manual PDF uploads via the dashboard.
113+
> **Note**: Option 1 provides local PDF upload capabilities, while Option 2 only supports PDF processing via URLs (no local file uploads).
95114
96115
## Available Tools
97116

manifest.json

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"display_name": "PageIndex",
55
"version": "1.2.0",
66
"description": "MCP server for PageIndex",
7-
"long_description": "This extension provides access to PageIndex's next-generation reasoning-based RAG system. Unlike traditional vector search, PageIndex uses multi-step reasoning to understand and retrieve information from documents.",
7+
"long_description": "This extension provides access to PageIndex's next-generation reasoning-based RAG system. Unlike traditional vector search, PageIndex uses multi-step reasoning to understand and retrieve information from documents. Authentication is handled automatically via OAuth 2.1.",
88
"author": {
99
"name": "VectifyAI",
1010
"url": "https://github.com/VectifyAI"
@@ -19,7 +19,8 @@
1919
"document-processing",
2020
"pdf",
2121
"ocr",
22-
"reasoning-rag"
22+
"reasoning-rag",
23+
"oauth"
2324
],
2425
"license": "MIT",
2526
"compatibility": {
@@ -34,26 +35,7 @@
3435
"entry_point": "build/index.js",
3536
"mcp_config": {
3637
"command": "node",
37-
"args": ["${__dirname}/build/index.js"],
38-
"env": {
39-
"PAGEINDEX_API_KEY": "${user_config.api_key}",
40-
"PAGEINDEX_API_URL": "${user_config.api_url}"
41-
}
42-
}
43-
},
44-
"user_config": {
45-
"api_key": {
46-
"type": "string",
47-
"title": "PageIndex API Key",
48-
"description": "Your PageIndex API key. Get one at https://dash.pageindex.ai/api-keys",
49-
"required": true
50-
},
51-
"api_url": {
52-
"type": "string",
53-
"title": "PageIndex API URL",
54-
"description": "PageIndex API base URL (optional, defaults to https://dash.pageindex.ai)",
55-
"required": false,
56-
"default": "https://dash.pageindex.ai"
38+
"args": ["${__dirname}/build/index.js"]
5739
}
5840
}
5941
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,12 @@
3232
"license": "MIT",
3333
"dependencies": {
3434
"@modelcontextprotocol/sdk": "^1.17.3",
35+
"@types/lodash": "^4.17.20",
3536
"date-fns": "^4.1.0",
37+
"lodash": "^4.17.21",
3638
"mime-types": "^2.1.35",
3739
"p-retry": "^7.0.0",
40+
"pkce-challenge": "^5.0.0",
3841
"zod": "^3.23.8",
3942
"zod-to-json-schema": "^3.24.6"
4043
},

pnpm-lock.yaml

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/client/auth.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,37 @@
1+
import type { OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
12
import type { FetchLike } from '@modelcontextprotocol/sdk/shared/transport.js';
23

34
/**
4-
* Creates an authenticated fetch function that adds Bearer token authentication
5-
* This is a simplified approach compared to implementing the complex OAuth interface
5+
* Creates an OAuth-authenticated fetch function that adds Bearer token authentication
6+
* using OAuth access tokens with automatic refresh capability
67
*/
7-
export function createAuthenticatedFetch(
8-
apiKey: string,
8+
export function createOAuthAuthenticatedFetch(
9+
getTokens: () => Promise<OAuthTokens | undefined>,
910
additionalHeaders: Record<string, string> = {},
1011
): FetchLike {
1112
return async (input: string | URL, init?: RequestInit): Promise<Response> => {
13+
const tokens = await getTokens();
14+
if (!tokens?.access_token) {
15+
throw new Error('No valid OAuth access token available');
16+
}
17+
1218
const headers = new Headers(init?.headers);
13-
headers.set('Authorization', `Bearer ${apiKey}`);
19+
headers.set('Authorization', `Bearer ${tokens.access_token}`);
1420

15-
// Add additional headers (like client identification)
1621
Object.entries(additionalHeaders).forEach(([key, value]) => {
1722
headers.set(key, value);
1823
});
1924

20-
return fetch(input, {
25+
const response = await fetch(input, {
2126
...init,
2227
headers,
2328
});
29+
30+
// If we get 401 Unauthorized, the token has expired
31+
if (response.status === 401) {
32+
throw new Error('TOKEN_EXPIRED');
33+
}
34+
35+
return response;
2436
};
2537
}

0 commit comments

Comments
 (0)