@iflow-mcp/apple-rag-mcp 4.6.2

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 (148) hide show
  1. package/.github/workflows/release.yml +62 -0
  2. package/.releaserc.json +38 -0
  3. package/CHANGELOG.md +161 -0
  4. package/README.md +114 -0
  5. package/README.zh-CN.md +119 -0
  6. package/apple-rag-mcp_process.log +8 -0
  7. package/biome.json +59 -0
  8. package/dist/src/auth/auth-middleware.d.ts +26 -0
  9. package/dist/src/auth/auth-middleware.d.ts.map +1 -0
  10. package/dist/src/auth/auth-middleware.js +77 -0
  11. package/dist/src/auth/auth-middleware.js.map +1 -0
  12. package/dist/src/auth/token-validator.d.ts +22 -0
  13. package/dist/src/auth/token-validator.d.ts.map +1 -0
  14. package/dist/src/auth/token-validator.js +64 -0
  15. package/dist/src/auth/token-validator.js.map +1 -0
  16. package/dist/src/mcp/formatters/response-formatter.d.ts +26 -0
  17. package/dist/src/mcp/formatters/response-formatter.d.ts.map +1 -0
  18. package/dist/src/mcp/formatters/response-formatter.js +119 -0
  19. package/dist/src/mcp/formatters/response-formatter.js.map +1 -0
  20. package/dist/src/mcp/manifest.d.ts +48 -0
  21. package/dist/src/mcp/manifest.d.ts.map +1 -0
  22. package/dist/src/mcp/manifest.js +46 -0
  23. package/dist/src/mcp/manifest.js.map +1 -0
  24. package/dist/src/mcp/middleware/request-validator.d.ts +48 -0
  25. package/dist/src/mcp/middleware/request-validator.d.ts.map +1 -0
  26. package/dist/src/mcp/middleware/request-validator.js +102 -0
  27. package/dist/src/mcp/middleware/request-validator.js.map +1 -0
  28. package/dist/src/mcp/protocol-handler.d.ts +70 -0
  29. package/dist/src/mcp/protocol-handler.d.ts.map +1 -0
  30. package/dist/src/mcp/protocol-handler.js +285 -0
  31. package/dist/src/mcp/protocol-handler.js.map +1 -0
  32. package/dist/src/mcp/tools/fetch-tool.d.ts +18 -0
  33. package/dist/src/mcp/tools/fetch-tool.d.ts.map +1 -0
  34. package/dist/src/mcp/tools/fetch-tool.js +76 -0
  35. package/dist/src/mcp/tools/fetch-tool.js.map +1 -0
  36. package/dist/src/mcp/tools/search-tool.d.ts +20 -0
  37. package/dist/src/mcp/tools/search-tool.d.ts.map +1 -0
  38. package/dist/src/mcp/tools/search-tool.js +86 -0
  39. package/dist/src/mcp/tools/search-tool.js.map +1 -0
  40. package/dist/src/services/database.d.ts +37 -0
  41. package/dist/src/services/database.d.ts.map +1 -0
  42. package/dist/src/services/database.js +166 -0
  43. package/dist/src/services/database.js.map +1 -0
  44. package/dist/src/services/deepinfra-base.d.ts +22 -0
  45. package/dist/src/services/deepinfra-base.d.ts.map +1 -0
  46. package/dist/src/services/deepinfra-base.js +55 -0
  47. package/dist/src/services/deepinfra-base.js.map +1 -0
  48. package/dist/src/services/embedding.d.ts +44 -0
  49. package/dist/src/services/embedding.d.ts.map +1 -0
  50. package/dist/src/services/embedding.js +61 -0
  51. package/dist/src/services/embedding.js.map +1 -0
  52. package/dist/src/services/index.d.ts +10 -0
  53. package/dist/src/services/index.d.ts.map +1 -0
  54. package/dist/src/services/index.js +52 -0
  55. package/dist/src/services/index.js.map +1 -0
  56. package/dist/src/services/ip-authentication.d.ts +12 -0
  57. package/dist/src/services/ip-authentication.d.ts.map +1 -0
  58. package/dist/src/services/ip-authentication.js +39 -0
  59. package/dist/src/services/ip-authentication.js.map +1 -0
  60. package/dist/src/services/rag.d.ts +35 -0
  61. package/dist/src/services/rag.d.ts.map +1 -0
  62. package/dist/src/services/rag.js +106 -0
  63. package/dist/src/services/rag.js.map +1 -0
  64. package/dist/src/services/rate-limit.d.ts +27 -0
  65. package/dist/src/services/rate-limit.d.ts.map +1 -0
  66. package/dist/src/services/rate-limit.js +91 -0
  67. package/dist/src/services/rate-limit.js.map +1 -0
  68. package/dist/src/services/reranker.d.ts +40 -0
  69. package/dist/src/services/reranker.d.ts.map +1 -0
  70. package/dist/src/services/reranker.js +97 -0
  71. package/dist/src/services/reranker.js.map +1 -0
  72. package/dist/src/services/search-engine.d.ts +89 -0
  73. package/dist/src/services/search-engine.d.ts.map +1 -0
  74. package/dist/src/services/search-engine.js +225 -0
  75. package/dist/src/services/search-engine.js.map +1 -0
  76. package/dist/src/services/tool-call-logger.d.ts +36 -0
  77. package/dist/src/services/tool-call-logger.d.ts.map +1 -0
  78. package/dist/src/services/tool-call-logger.js +34 -0
  79. package/dist/src/services/tool-call-logger.js.map +1 -0
  80. package/dist/src/types/env.d.ts +18 -0
  81. package/dist/src/types/env.d.ts.map +1 -0
  82. package/dist/src/types/env.js +2 -0
  83. package/dist/src/types/env.js.map +1 -0
  84. package/dist/src/types/index.d.ts +145 -0
  85. package/dist/src/types/index.d.ts.map +1 -0
  86. package/dist/src/types/index.js +6 -0
  87. package/dist/src/types/index.js.map +1 -0
  88. package/dist/src/utils/d1-utils.d.ts +6 -0
  89. package/dist/src/utils/d1-utils.d.ts.map +1 -0
  90. package/dist/src/utils/d1-utils.js +29 -0
  91. package/dist/src/utils/d1-utils.js.map +1 -0
  92. package/dist/src/utils/logger.d.ts +11 -0
  93. package/dist/src/utils/logger.d.ts.map +1 -0
  94. package/dist/src/utils/logger.js +26 -0
  95. package/dist/src/utils/logger.js.map +1 -0
  96. package/dist/src/utils/query-cleaner.d.ts +20 -0
  97. package/dist/src/utils/query-cleaner.d.ts.map +1 -0
  98. package/dist/src/utils/query-cleaner.js +117 -0
  99. package/dist/src/utils/query-cleaner.js.map +1 -0
  100. package/dist/src/utils/request-info.d.ts +18 -0
  101. package/dist/src/utils/request-info.d.ts.map +1 -0
  102. package/dist/src/utils/request-info.js +32 -0
  103. package/dist/src/utils/request-info.js.map +1 -0
  104. package/dist/src/utils/telegram-notifier.d.ts +4 -0
  105. package/dist/src/utils/telegram-notifier.d.ts.map +1 -0
  106. package/dist/src/utils/telegram-notifier.js +33 -0
  107. package/dist/src/utils/telegram-notifier.js.map +1 -0
  108. package/dist/src/utils/url-processor.d.ts +15 -0
  109. package/dist/src/utils/url-processor.d.ts.map +1 -0
  110. package/dist/src/utils/url-processor.js +54 -0
  111. package/dist/src/utils/url-processor.js.map +1 -0
  112. package/dist/src/worker.d.ts +15 -0
  113. package/dist/src/worker.d.ts.map +1 -0
  114. package/dist/src/worker.js +136 -0
  115. package/dist/src/worker.js.map +1 -0
  116. package/migrations/schema.sql +155 -0
  117. package/package.json +49 -0
  118. package/scripts/semantic-release-server-json.js +34 -0
  119. package/server.json +25 -0
  120. package/src/auth/auth-middleware.ts +104 -0
  121. package/src/auth/token-validator.ts +96 -0
  122. package/src/mcp/formatters/response-formatter.ts +157 -0
  123. package/src/mcp/manifest.ts +48 -0
  124. package/src/mcp/middleware/request-validator.ts +135 -0
  125. package/src/mcp/protocol-handler.ts +412 -0
  126. package/src/mcp/tools/fetch-tool.ts +146 -0
  127. package/src/mcp/tools/search-tool.ts +165 -0
  128. package/src/services/database.ts +202 -0
  129. package/src/services/deepinfra-base.ts +81 -0
  130. package/src/services/embedding.ts +96 -0
  131. package/src/services/index.ts +59 -0
  132. package/src/services/ip-authentication.ts +62 -0
  133. package/src/services/rag.ts +158 -0
  134. package/src/services/rate-limit.ts +141 -0
  135. package/src/services/reranker.ts +171 -0
  136. package/src/services/search-engine.ts +333 -0
  137. package/src/services/tool-call-logger.ts +98 -0
  138. package/src/types/env.ts +22 -0
  139. package/src/types/index.ts +189 -0
  140. package/src/utils/d1-utils.ts +45 -0
  141. package/src/utils/logger.ts +33 -0
  142. package/src/utils/query-cleaner.ts +151 -0
  143. package/src/utils/request-info.ts +47 -0
  144. package/src/utils/telegram-notifier.ts +47 -0
  145. package/src/utils/url-processor.ts +65 -0
  146. package/src/worker.ts +176 -0
  147. package/tsconfig.json +32 -0
  148. package/wrangler.toml.example +39 -0
@@ -0,0 +1,96 @@
1
+ /**
2
+ * MCP Token Validator with D1 timeout protection
3
+ */
4
+
5
+ import { backgroundD1Write, withD1Timeout } from "../utils/d1-utils.js";
6
+ import { logger } from "../utils/logger.js";
7
+
8
+ export interface TokenValidationResult {
9
+ valid: boolean;
10
+ error?: string;
11
+ userData?: UserTokenData;
12
+ }
13
+
14
+ export interface UserTokenData {
15
+ userId: string;
16
+ email: string;
17
+ name: string;
18
+ }
19
+
20
+ export class TokenValidator {
21
+ constructor(private d1: D1Database) {}
22
+
23
+ async validateToken(token: string): Promise<TokenValidationResult> {
24
+ if (!/^at_[a-f0-9]{32}$/.test(token)) {
25
+ return { valid: false, error: "Invalid token format" };
26
+ }
27
+
28
+ const userData = await withD1Timeout(
29
+ () => this.queryUserByToken(token),
30
+ null,
31
+ "token_lookup"
32
+ );
33
+
34
+ if (!userData) {
35
+ return { valid: false, error: "Token not found" };
36
+ }
37
+
38
+ backgroundD1Write(
39
+ logger.getContext(),
40
+ () => this.updateLastUsed(token),
41
+ "token_last_used"
42
+ );
43
+
44
+ return { valid: true, userData };
45
+ }
46
+
47
+ private async queryUserByToken(token: string): Promise<UserTokenData | null> {
48
+ const result = await this.d1
49
+ .prepare(
50
+ `SELECT u.id as user_id, u.email, u.name
51
+ FROM mcp_tokens t JOIN users u ON t.user_id = u.id
52
+ WHERE t.mcp_token = ?`
53
+ )
54
+ .bind(token)
55
+ .all();
56
+
57
+ if (!result.success || !result.results?.length) return null;
58
+
59
+ const row = result.results[0] as Record<string, unknown>;
60
+ return {
61
+ userId: row.user_id as string,
62
+ email: (row.email as string) || "unknown",
63
+ name: (row.name as string) || "unknown",
64
+ };
65
+ }
66
+
67
+ private async updateLastUsed(token: string): Promise<void> {
68
+ await this.d1
69
+ .prepare("UPDATE mcp_tokens SET last_used_at = ? WHERE mcp_token = ?")
70
+ .bind(new Date().toISOString(), token)
71
+ .run();
72
+ }
73
+
74
+ async getUserDataById(userId: string): Promise<UserTokenData> {
75
+ const result = await withD1Timeout(
76
+ async () => {
77
+ const res = await this.d1
78
+ .prepare("SELECT id, email, name FROM users WHERE id = ?")
79
+ .bind(userId)
80
+ .all();
81
+ if (!res.success || !res.results?.length) throw new Error("User not found");
82
+ const user = res.results[0] as Record<string, unknown>;
83
+ return {
84
+ userId: user.id as string,
85
+ email: user.email as string,
86
+ name: (user.name as string) || (user.email as string).split("@")[0],
87
+ };
88
+ },
89
+ null,
90
+ "user_lookup"
91
+ );
92
+
93
+ if (!result) throw new Error("User not found");
94
+ return result;
95
+ }
96
+ }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Response Formatting Utilities
3
+ * Professional response formatting for MCP protocol
4
+ */
5
+
6
+ import type { MCPResponse, RAGResult } from "../../types/index.js";
7
+ import { APP_CONSTANTS } from "../protocol-handler.js";
8
+
9
+ /**
10
+ * Format RAG response with professional layout
11
+ */
12
+ export function formatRAGResponse(
13
+ ragResult: RAGResult,
14
+ isAuthenticated: boolean,
15
+ wasAdjusted: boolean = false
16
+ ): string {
17
+ if (
18
+ !ragResult ||
19
+ !ragResult.success ||
20
+ !ragResult.results ||
21
+ ragResult.results.length === 0
22
+ ) {
23
+ return APP_CONSTANTS.NO_RESULTS_MESSAGE;
24
+ }
25
+
26
+ const results = ragResult.results;
27
+ let response = "";
28
+
29
+ results.forEach((result, index) => {
30
+ let title = `[${index + 1}] ${result.title || "Untitled"}`;
31
+
32
+ // Add completeness indicator based on chunk information and merge status
33
+ const isMerged =
34
+ result.mergedChunkIndices && result.mergedChunkIndices.length > 1;
35
+
36
+ if (result.total_chunks === 1) {
37
+ title += ` ✅ Complete Document`;
38
+ response += `${title}\n\n`;
39
+ } else if (isMerged) {
40
+ // For merged content, show which specific parts are included
41
+ const mergedParts = result
42
+ .mergedChunkIndices!.map((idx) => idx + 1)
43
+ .join(", ");
44
+ title += ` 📄 Parts ${mergedParts} merged (${result.total_chunks} total)`;
45
+ response += `${title}\n\n`;
46
+ response += `This shows merged content from multiple parts. For the complete document, use Apple RAG MCP fetch tool: \`fetch(url: "${result.url}")\`\n\n`;
47
+ } else {
48
+ title += ` 📄 Part ${result.chunk_index + 1} of ${result.total_chunks}`;
49
+ response += `${title}\n\n`;
50
+ response += `This is a partial document. For the complete content, use Apple RAG MCP fetch tool: \`fetch(url: "${result.url}")\`\n\n`;
51
+ }
52
+
53
+ response += `${result.content}\n`;
54
+
55
+ if (index < results.length - 1) {
56
+ response += `\n${"─".repeat(80)}\n\n`;
57
+ }
58
+ });
59
+
60
+ // Additional URLs section
61
+ if (ragResult.additionalUrls && ragResult.additionalUrls.length > 0) {
62
+ response += `\n\n${"─".repeat(60)}\n\n`;
63
+ response += `Additional Related Documentation:\n`;
64
+ response += `The following ${ragResult.additionalUrls.length} URLs contain supplementary information that may provide additional context or related topics. This includes Apple developer documentation and WWDC video transcripts. Use the \`fetch\` tool to retrieve their complete, cleaned content:\n\n`;
65
+
66
+ ragResult.additionalUrls.forEach((item) => {
67
+ response += `${item.url}\n`;
68
+
69
+ // Show title for Apple Developer video URLs
70
+ if (item.title && item.url.includes("developer.apple.com/videos/play/")) {
71
+ response += ` └─ ${item.title}\n`;
72
+ }
73
+
74
+ response += ` └─ ${item.characterCount} characters\n\n`;
75
+ });
76
+ }
77
+
78
+ // Footer message for anonymous users
79
+ if (!isAuthenticated) {
80
+ response += `\n\n${APP_CONSTANTS.ANONYMOUS_ACCESS_MESSAGE}`;
81
+ }
82
+
83
+ // Parameter range reminder for AI agents (only when parameter was adjusted)
84
+ if (wasAdjusted) {
85
+ response += `\n\nNote: The result_count parameter accepts values between 1 and 10. Values outside this range are automatically adjusted to the nearest valid limit.`;
86
+ }
87
+
88
+ return response;
89
+ }
90
+
91
+ /**
92
+ * Format fetch response with professional styling
93
+ */
94
+ export function formatFetchResponse(
95
+ result: { success?: boolean; title?: string; content?: string },
96
+ isAuthenticated: boolean
97
+ ): string {
98
+ if (!result || !result.success) {
99
+ return "Failed to retrieve content from the specified URL.";
100
+ }
101
+
102
+ let response = "";
103
+
104
+ if (result.title) {
105
+ response += `${result.title}\n\n`;
106
+ }
107
+
108
+ if (result.content) {
109
+ response += result.content;
110
+ }
111
+
112
+ // Footer message for anonymous users
113
+ if (!isAuthenticated) {
114
+ response += `\n\n${APP_CONSTANTS.ANONYMOUS_ACCESS_MESSAGE}`;
115
+ }
116
+
117
+ return response;
118
+ }
119
+
120
+ /**
121
+ * Create success response
122
+ */
123
+ export function createSuccessResponse(
124
+ requestId: string | number,
125
+ content: string
126
+ ): MCPResponse {
127
+ return {
128
+ jsonrpc: "2.0",
129
+ id: requestId,
130
+ result: {
131
+ content: [
132
+ {
133
+ type: "text",
134
+ text: content,
135
+ },
136
+ ],
137
+ },
138
+ };
139
+ }
140
+
141
+ /**
142
+ * Create error response
143
+ */
144
+ export function createErrorResponse(
145
+ requestId: string | number,
146
+ code: number,
147
+ message: string
148
+ ): MCPResponse {
149
+ return {
150
+ jsonrpc: "2.0",
151
+ id: requestId,
152
+ error: {
153
+ code,
154
+ message,
155
+ },
156
+ };
157
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * MCP Server Manifest
3
+ * Centralized server discovery and capability information
4
+ */
5
+
6
+ export const SERVER_MANIFEST = {
7
+ name: "Apple RAG MCP Server",
8
+ title: "Apple Developer Documentation Search",
9
+ version: "2.0.0",
10
+ description:
11
+ "Ultra-modern MCP server providing AI agents with comprehensive access to Apple's complete developer documentation using advanced RAG technology.",
12
+ protocolVersion: "2025-06-18",
13
+ supportedVersions: ["2025-06-18", "2025-03-26"],
14
+ capabilities: {
15
+ tools: { listChanged: true },
16
+ logging: {},
17
+ experimental: {},
18
+ },
19
+ serverInfo: {
20
+ name: "Apple RAG MCP Server",
21
+ version: "2.0.0",
22
+ },
23
+ endpoints: {
24
+ mcp: "/",
25
+ manifest: "/manifest",
26
+ health: "/health",
27
+ },
28
+ transport: {
29
+ type: "http",
30
+ methods: ["POST"],
31
+ headers: {
32
+ required: ["Content-Type"],
33
+ optional: ["Authorization", "MCP-Protocol-Version"],
34
+ },
35
+ },
36
+ authorization: {
37
+ enabled: true,
38
+ type: "bearer",
39
+ optional: true,
40
+ },
41
+ } as const;
42
+
43
+ export const HEALTH_STATUS = {
44
+ status: "healthy",
45
+ version: "2.0.0",
46
+ protocol: "2025-06-18",
47
+ supportedVersions: ["2025-06-18", "2025-03-26"],
48
+ } as const;
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Request Validation Middleware
3
+ * Validates MCP protocol requests and parameters
4
+ */
5
+
6
+ import type { MCPNotification, MCPRequest } from "../../types/index.js";
7
+ import {
8
+ MCP_ERROR_CODES,
9
+ SUPPORTED_MCP_VERSIONS,
10
+ } from "../protocol-handler.js";
11
+
12
+ /**
13
+ * Validate MCP request structure
14
+ */
15
+ export function isValidMCPRequest(body: unknown): body is MCPRequest {
16
+ return (
17
+ body != null &&
18
+ typeof body === "object" &&
19
+ "jsonrpc" in body &&
20
+ (body as Record<string, unknown>).jsonrpc === "2.0" &&
21
+ "id" in body &&
22
+ "method" in body &&
23
+ typeof (body as Record<string, unknown>).method === "string"
24
+ );
25
+ }
26
+
27
+ /**
28
+ * Validate MCP notification structure
29
+ */
30
+ export function isValidMCPNotification(body: unknown): body is MCPNotification {
31
+ return (
32
+ body != null &&
33
+ typeof body === "object" &&
34
+ "jsonrpc" in body &&
35
+ (body as Record<string, unknown>).jsonrpc === "2.0" &&
36
+ "method" in body &&
37
+ typeof (body as Record<string, unknown>).method === "string" &&
38
+ !("id" in body)
39
+ );
40
+ }
41
+
42
+ /**
43
+ * Validate protocol version
44
+ */
45
+ export function validateProtocolVersion(version?: string): {
46
+ isValid: boolean;
47
+ error?: { code: number; message: string };
48
+ } {
49
+ if (
50
+ version &&
51
+ !SUPPORTED_MCP_VERSIONS.includes(
52
+ version as (typeof SUPPORTED_MCP_VERSIONS)[number]
53
+ )
54
+ ) {
55
+ return {
56
+ isValid: false,
57
+ error: {
58
+ code: MCP_ERROR_CODES.INVALID_PARAMS,
59
+ message: `Unsupported protocol version: ${version}. Supported versions: ${SUPPORTED_MCP_VERSIONS.join(", ")}`,
60
+ },
61
+ };
62
+ }
63
+
64
+ return { isValid: true };
65
+ }
66
+
67
+ /**
68
+ * Validate initialize parameters
69
+ */
70
+ export function validateInitializeParams(params: unknown): {
71
+ isValid: boolean;
72
+ error?: { code: number; message: string };
73
+ } {
74
+ // Basic validation - can be extended
75
+ if (params && typeof params !== "object") {
76
+ return {
77
+ isValid: false,
78
+ error: {
79
+ code: MCP_ERROR_CODES.INVALID_PARAMS,
80
+ message: "Initialize parameters must be an object",
81
+ },
82
+ };
83
+ }
84
+
85
+ return { isValid: true };
86
+ }
87
+
88
+ /**
89
+ * Validate tool call parameters
90
+ */
91
+ export function validateToolCallParams(params: unknown): {
92
+ isValid: boolean;
93
+ toolCall?: { name: string; arguments?: Record<string, unknown> };
94
+ error?: { code: number; message: string };
95
+ } {
96
+ if (!params || typeof params !== "object") {
97
+ return {
98
+ isValid: false,
99
+ error: {
100
+ code: MCP_ERROR_CODES.INVALID_PARAMS,
101
+ message: "Tool call parameters are required",
102
+ },
103
+ };
104
+ }
105
+
106
+ const p = params as Record<string, unknown>;
107
+
108
+ if (!p.name || typeof p.name !== "string") {
109
+ return {
110
+ isValid: false,
111
+ error: {
112
+ code: MCP_ERROR_CODES.INVALID_PARAMS,
113
+ message: "Tool name is required and must be a string",
114
+ },
115
+ };
116
+ }
117
+
118
+ if (!p.arguments || typeof p.arguments !== "object") {
119
+ return {
120
+ isValid: false,
121
+ error: {
122
+ code: MCP_ERROR_CODES.INVALID_PARAMS,
123
+ message: "Tool arguments are required and must be an object",
124
+ },
125
+ };
126
+ }
127
+
128
+ return {
129
+ isValid: true,
130
+ toolCall: {
131
+ name: p.name,
132
+ arguments: p.arguments as Record<string, unknown>,
133
+ },
134
+ };
135
+ }