@cyanheads/pubmed-mcp-server 1.0.12
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.
- package/LICENSE +201 -0
- package/README.md +174 -0
- package/dist/config/index.d.ts +91 -0
- package/dist/config/index.js +324 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +190 -0
- package/dist/mcp-server/resources/echoResource/echoResourceLogic.d.ts +79 -0
- package/dist/mcp-server/resources/echoResource/echoResourceLogic.js +82 -0
- package/dist/mcp-server/resources/echoResource/index.d.ts +13 -0
- package/dist/mcp-server/resources/echoResource/index.js +13 -0
- package/dist/mcp-server/resources/echoResource/registration.d.ts +30 -0
- package/dist/mcp-server/resources/echoResource/registration.js +168 -0
- package/dist/mcp-server/server.d.ts +28 -0
- package/dist/mcp-server/server.js +159 -0
- package/dist/mcp-server/tools/fetchPubMedContent/index.d.ts +6 -0
- package/dist/mcp-server/tools/fetchPubMedContent/index.js +6 -0
- package/dist/mcp-server/tools/fetchPubMedContent/logic.d.ts +63 -0
- package/dist/mcp-server/tools/fetchPubMedContent/logic.js +518 -0
- package/dist/mcp-server/tools/fetchPubMedContent/registration.d.ts +10 -0
- package/dist/mcp-server/tools/fetchPubMedContent/registration.js +37 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/index.d.ts +6 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/index.js +6 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic/citationFormatter.d.ts +9 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic/citationFormatter.js +288 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic/elinkHandler.d.ts +9 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic/elinkHandler.js +208 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic/index.d.ts +15 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic/index.js +82 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic/types.d.ts +27 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic/types.js +5 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic.d.ts +6 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/logic.js +6 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/registration.d.ts +36 -0
- package/dist/mcp-server/tools/getPubMedArticleConnections/registration.js +76 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/index.d.ts +6 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/index.js +6 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/logic/index.d.ts +7 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/logic/index.js +9 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/logic/inputSchema.d.ts +111 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/logic/inputSchema.js +149 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/logic/outputTypes.d.ts +106 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/logic/outputTypes.js +7 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/logic/planOrchestrator.d.ts +10 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/logic/planOrchestrator.js +251 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/logic.d.ts +12 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/logic.js +55 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/registration.d.ts +10 -0
- package/dist/mcp-server/tools/pubmedResearchAgent/registration.js +36 -0
- package/dist/mcp-server/tools/searchPubMedArticles/index.d.ts +6 -0
- package/dist/mcp-server/tools/searchPubMedArticles/index.js +6 -0
- package/dist/mcp-server/tools/searchPubMedArticles/logic.d.ts +61 -0
- package/dist/mcp-server/tools/searchPubMedArticles/logic.js +229 -0
- package/dist/mcp-server/tools/searchPubMedArticles/registration.d.ts +10 -0
- package/dist/mcp-server/tools/searchPubMedArticles/registration.js +38 -0
- package/dist/mcp-server/transports/authentication/authMiddleware.d.ts +29 -0
- package/dist/mcp-server/transports/authentication/authMiddleware.js +174 -0
- package/dist/mcp-server/transports/httpTransport.d.ts +23 -0
- package/dist/mcp-server/transports/httpTransport.js +463 -0
- package/dist/mcp-server/transports/stdioTransport.d.ts +42 -0
- package/dist/mcp-server/transports/stdioTransport.js +63 -0
- package/dist/services/NCBI/ncbiConstants.d.ts +22 -0
- package/dist/services/NCBI/ncbiConstants.js +5 -0
- package/dist/services/NCBI/ncbiCoreApiClient.d.ts +24 -0
- package/dist/services/NCBI/ncbiCoreApiClient.js +118 -0
- package/dist/services/NCBI/ncbiRequestQueueManager.d.ts +36 -0
- package/dist/services/NCBI/ncbiRequestQueueManager.js +96 -0
- package/dist/services/NCBI/ncbiResponseHandler.d.ts +22 -0
- package/dist/services/NCBI/ncbiResponseHandler.js +192 -0
- package/dist/services/NCBI/ncbiService.d.ts +24 -0
- package/dist/services/NCBI/ncbiService.js +57 -0
- package/dist/services/index.d.ts +7 -0
- package/dist/services/index.js +7 -0
- package/dist/services/llm-providers/index.d.ts +7 -0
- package/dist/services/llm-providers/index.js +7 -0
- package/dist/services/llm-providers/llmFactory.d.ts +69 -0
- package/dist/services/llm-providers/llmFactory.js +132 -0
- package/dist/services/llm-providers/openRouter/index.d.ts +6 -0
- package/dist/services/llm-providers/openRouter/index.js +7 -0
- package/dist/services/llm-providers/openRouter/openRouterProvider.d.ts +99 -0
- package/dist/services/llm-providers/openRouter/openRouterProvider.js +329 -0
- package/dist/types-global/errors.d.ts +119 -0
- package/dist/types-global/errors.js +119 -0
- package/dist/types-global/pubmedXml.d.ts +350 -0
- package/dist/types-global/pubmedXml.js +7 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/internal/errorHandler.d.ts +176 -0
- package/dist/utils/internal/errorHandler.js +335 -0
- package/dist/utils/internal/index.d.ts +9 -0
- package/dist/utils/internal/index.js +9 -0
- package/dist/utils/internal/logger.d.ts +141 -0
- package/dist/utils/internal/logger.js +426 -0
- package/dist/utils/internal/requestContext.d.ts +83 -0
- package/dist/utils/internal/requestContext.js +72 -0
- package/dist/utils/metrics/index.d.ts +7 -0
- package/dist/utils/metrics/index.js +7 -0
- package/dist/utils/metrics/tokenCounter.d.ts +35 -0
- package/dist/utils/metrics/tokenCounter.js +110 -0
- package/dist/utils/parsing/dateParser.d.ts +73 -0
- package/dist/utils/parsing/dateParser.js +107 -0
- package/dist/utils/parsing/index.d.ts +8 -0
- package/dist/utils/parsing/index.js +8 -0
- package/dist/utils/parsing/jsonParser.d.ts +82 -0
- package/dist/utils/parsing/jsonParser.js +126 -0
- package/dist/utils/parsing/ncbi-parsing/eSummaryResultParser.d.ts +32 -0
- package/dist/utils/parsing/ncbi-parsing/eSummaryResultParser.js +295 -0
- package/dist/utils/parsing/ncbi-parsing/index.d.ts +8 -0
- package/dist/utils/parsing/ncbi-parsing/index.js +8 -0
- package/dist/utils/parsing/ncbi-parsing/pubmedArticleStructureParser.d.ts +70 -0
- package/dist/utils/parsing/ncbi-parsing/pubmedArticleStructureParser.js +229 -0
- package/dist/utils/parsing/ncbi-parsing/xmlGenericHelpers.d.ts +31 -0
- package/dist/utils/parsing/ncbi-parsing/xmlGenericHelpers.js +76 -0
- package/dist/utils/security/idGenerator.d.ts +134 -0
- package/dist/utils/security/idGenerator.js +198 -0
- package/dist/utils/security/index.d.ts +9 -0
- package/dist/utils/security/index.js +9 -0
- package/dist/utils/security/rateLimiter.d.ts +108 -0
- package/dist/utils/security/rateLimiter.js +179 -0
- package/dist/utils/security/sanitization.d.ts +173 -0
- package/dist/utils/security/sanitization.js +439 -0
- package/package.json +97 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Loads, validates, and exports application configuration.
|
|
3
|
+
* This module centralizes configuration management, sourcing values from
|
|
4
|
+
* environment variables and `package.json`. It uses Zod for schema validation
|
|
5
|
+
* to ensure type safety and correctness of configuration parameters.
|
|
6
|
+
*
|
|
7
|
+
* Key responsibilities:
|
|
8
|
+
* - Load environment variables from a `.env` file.
|
|
9
|
+
* - Read `package.json` for default server name and version.
|
|
10
|
+
* - Define a Zod schema for all expected environment variables.
|
|
11
|
+
* - Validate environment variables against the schema.
|
|
12
|
+
* - Construct and export a comprehensive `config` object.
|
|
13
|
+
* - Export individual configuration values like `logLevel` and `environment` for convenience.
|
|
14
|
+
*
|
|
15
|
+
* @module src/config/index
|
|
16
|
+
*/
|
|
17
|
+
import dotenv from "dotenv";
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, statSync } from "fs";
|
|
19
|
+
import path, { dirname, join } from "path";
|
|
20
|
+
import { fileURLToPath } from "url";
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
dotenv.config();
|
|
23
|
+
// --- Determine Project Root ---
|
|
24
|
+
/**
|
|
25
|
+
* Finds the project root directory by searching upwards for package.json.
|
|
26
|
+
* @param startDir The directory to start searching from.
|
|
27
|
+
* @returns The absolute path to the project root, or throws an error if not found.
|
|
28
|
+
*/
|
|
29
|
+
const findProjectRoot = (startDir) => {
|
|
30
|
+
let currentDir = startDir;
|
|
31
|
+
while (true) {
|
|
32
|
+
const packageJsonPath = join(currentDir, "package.json");
|
|
33
|
+
if (existsSync(packageJsonPath)) {
|
|
34
|
+
return currentDir;
|
|
35
|
+
}
|
|
36
|
+
const parentDir = dirname(currentDir);
|
|
37
|
+
if (parentDir === currentDir) {
|
|
38
|
+
// Reached the root of the filesystem without finding package.json
|
|
39
|
+
throw new Error(`Could not find project root (package.json) starting from ${startDir}`);
|
|
40
|
+
}
|
|
41
|
+
currentDir = parentDir;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
let projectRoot;
|
|
45
|
+
try {
|
|
46
|
+
// For ESM, __dirname is not available directly.
|
|
47
|
+
// import.meta.url gives the URL of the current module.
|
|
48
|
+
const currentModuleDir = dirname(fileURLToPath(import.meta.url));
|
|
49
|
+
projectRoot = findProjectRoot(currentModuleDir);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
console.error(`FATAL: Error determining project root: ${error.message}`);
|
|
53
|
+
// Fallback to process.cwd() if project root cannot be determined.
|
|
54
|
+
// This might happen in unusual execution environments.
|
|
55
|
+
projectRoot = process.cwd();
|
|
56
|
+
console.warn(`Warning: Using process.cwd() (${projectRoot}) as fallback project root.`);
|
|
57
|
+
}
|
|
58
|
+
// --- End Determine Project Root ---
|
|
59
|
+
const pkgPath = join(projectRoot, "package.json"); // Use determined projectRoot
|
|
60
|
+
let pkg = { name: "mcp-ts-template", version: "0.0.0" };
|
|
61
|
+
try {
|
|
62
|
+
pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (process.stdout.isTTY) {
|
|
66
|
+
console.error("Warning: Could not read package.json for default config values. Using hardcoded defaults.", error);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Zod schema for validating environment variables.
|
|
71
|
+
* Provides type safety, validation, defaults, and clear error messages.
|
|
72
|
+
* @private
|
|
73
|
+
*/
|
|
74
|
+
const EnvSchema = z.object({
|
|
75
|
+
/** Optional. The desired name for the MCP server. Defaults to `package.json` name. */
|
|
76
|
+
MCP_SERVER_NAME: z.string().optional(),
|
|
77
|
+
/** Optional. The version of the MCP server. Defaults to `package.json` version. */
|
|
78
|
+
MCP_SERVER_VERSION: z.string().optional(),
|
|
79
|
+
/** Minimum logging level. See `McpLogLevel` in logger utility. Default: "debug". */
|
|
80
|
+
MCP_LOG_LEVEL: z.string().default("debug"),
|
|
81
|
+
/** Directory for log files. Defaults to "logs" in project root. */
|
|
82
|
+
LOGS_DIR: z.string().default(path.join(projectRoot, "logs")),
|
|
83
|
+
/** Runtime environment (e.g., "development", "production"). Default: "development". */
|
|
84
|
+
NODE_ENV: z.string().default("development"),
|
|
85
|
+
/** MCP communication transport ("stdio" or "http"). Default: "stdio". */
|
|
86
|
+
MCP_TRANSPORT_TYPE: z.enum(["stdio", "http"]).default("stdio"),
|
|
87
|
+
/** HTTP server port (if MCP_TRANSPORT_TYPE is "http"). Default: 3010. */
|
|
88
|
+
MCP_HTTP_PORT: z.coerce.number().int().positive().default(3010),
|
|
89
|
+
/** HTTP server host (if MCP_TRANSPORT_TYPE is "http"). Default: "127.0.0.1". */
|
|
90
|
+
MCP_HTTP_HOST: z.string().default("127.0.0.1"),
|
|
91
|
+
/** Optional. Comma-separated allowed origins for CORS (HTTP transport). */
|
|
92
|
+
MCP_ALLOWED_ORIGINS: z.string().optional(),
|
|
93
|
+
/** Optional. Secret key (min 32 chars) for auth tokens (HTTP transport). CRITICAL for production. */
|
|
94
|
+
MCP_AUTH_SECRET_KEY: z
|
|
95
|
+
.string()
|
|
96
|
+
.min(32, "MCP_AUTH_SECRET_KEY must be at least 32 characters long for security reasons.")
|
|
97
|
+
.optional(),
|
|
98
|
+
/** Optional. Application URL for OpenRouter integration. */
|
|
99
|
+
OPENROUTER_APP_URL: z
|
|
100
|
+
.string()
|
|
101
|
+
.url("OPENROUTER_APP_URL must be a valid URL (e.g., http://localhost:3000)")
|
|
102
|
+
.optional(),
|
|
103
|
+
/** Optional. Application name for OpenRouter. Defaults to MCP_SERVER_NAME or package name. */
|
|
104
|
+
OPENROUTER_APP_NAME: z.string().optional(),
|
|
105
|
+
/** Optional. API key for OpenRouter services. */
|
|
106
|
+
OPENROUTER_API_KEY: z.string().optional(),
|
|
107
|
+
/** Default LLM model. Default: "google/gemini-2.5-flash-preview:thinking". */
|
|
108
|
+
LLM_DEFAULT_MODEL: z
|
|
109
|
+
.string()
|
|
110
|
+
.default("google/gemini-2.5-flash-preview-05-20"),
|
|
111
|
+
/** Optional. Default LLM temperature (0.0-2.0). */
|
|
112
|
+
LLM_DEFAULT_TEMPERATURE: z.coerce.number().min(0).max(2).optional(),
|
|
113
|
+
/** Optional. Default LLM top_p (0.0-1.0). */
|
|
114
|
+
LLM_DEFAULT_TOP_P: z.coerce.number().min(0).max(1).optional(),
|
|
115
|
+
/** Optional. Default LLM max tokens (positive integer). */
|
|
116
|
+
LLM_DEFAULT_MAX_TOKENS: z.coerce.number().int().positive().optional(),
|
|
117
|
+
/** Optional. Default LLM top_k (non-negative integer). */
|
|
118
|
+
LLM_DEFAULT_TOP_K: z.coerce.number().int().nonnegative().optional(),
|
|
119
|
+
/** Optional. Default LLM min_p (0.0-1.0). */
|
|
120
|
+
LLM_DEFAULT_MIN_P: z.coerce.number().min(0).max(1).optional(),
|
|
121
|
+
/** Optional. API key for Google Gemini services. */
|
|
122
|
+
GEMINI_API_KEY: z.string().optional(),
|
|
123
|
+
/** Optional. OAuth provider authorization endpoint URL. */
|
|
124
|
+
OAUTH_PROXY_AUTHORIZATION_URL: z
|
|
125
|
+
.string()
|
|
126
|
+
.url("OAUTH_PROXY_AUTHORIZATION_URL must be a valid URL.")
|
|
127
|
+
.optional(),
|
|
128
|
+
/** Optional. OAuth provider token endpoint URL. */
|
|
129
|
+
OAUTH_PROXY_TOKEN_URL: z
|
|
130
|
+
.string()
|
|
131
|
+
.url("OAUTH_PROXY_TOKEN_URL must be a valid URL.")
|
|
132
|
+
.optional(),
|
|
133
|
+
/** Optional. OAuth provider revocation endpoint URL. */
|
|
134
|
+
OAUTH_PROXY_REVOCATION_URL: z
|
|
135
|
+
.string()
|
|
136
|
+
.url("OAUTH_PROXY_REVOCATION_URL must be a valid URL.")
|
|
137
|
+
.optional(),
|
|
138
|
+
/** Optional. OAuth provider issuer URL. */
|
|
139
|
+
OAUTH_PROXY_ISSUER_URL: z
|
|
140
|
+
.string()
|
|
141
|
+
.url("OAUTH_PROXY_ISSUER_URL must be a valid URL.")
|
|
142
|
+
.optional(),
|
|
143
|
+
/** Optional. OAuth service documentation URL. */
|
|
144
|
+
OAUTH_PROXY_SERVICE_DOCUMENTATION_URL: z
|
|
145
|
+
.string()
|
|
146
|
+
.url("OAUTH_PROXY_SERVICE_DOCUMENTATION_URL must be a valid URL.")
|
|
147
|
+
.optional(),
|
|
148
|
+
/** Optional. Comma-separated default OAuth client redirect URIs. */
|
|
149
|
+
OAUTH_PROXY_DEFAULT_CLIENT_REDIRECT_URIS: z.string().optional(),
|
|
150
|
+
// NCBI E-utilities Configuration
|
|
151
|
+
/** NCBI API Key. Optional, but highly recommended for higher rate limits. */
|
|
152
|
+
NCBI_API_KEY: z.string().optional(),
|
|
153
|
+
/** Tool identifier sent to NCBI. Defaults to MCP_SERVER_NAME/MCP_SERVER_VERSION. */
|
|
154
|
+
NCBI_TOOL_IDENTIFIER: z.string().optional(),
|
|
155
|
+
/** Administrator's email for NCBI contact. Optional, but recommended if using an API key. */
|
|
156
|
+
NCBI_ADMIN_EMAIL: z
|
|
157
|
+
.string()
|
|
158
|
+
.email("NCBI_ADMIN_EMAIL must be a valid email address.")
|
|
159
|
+
.optional(),
|
|
160
|
+
/** Milliseconds to wait between NCBI requests. Default: 100 (for API key), 334 (without API key). */
|
|
161
|
+
NCBI_REQUEST_DELAY_MS: z.coerce.number().int().positive().optional(), // Default will be set conditionally
|
|
162
|
+
/** Maximum number of retries for failed NCBI requests. Default: 3. */
|
|
163
|
+
NCBI_MAX_RETRIES: z.coerce.number().int().nonnegative().default(3),
|
|
164
|
+
});
|
|
165
|
+
const parsedEnv = EnvSchema.safeParse(process.env);
|
|
166
|
+
if (!parsedEnv.success) {
|
|
167
|
+
if (process.stdout.isTTY) {
|
|
168
|
+
console.error("❌ Invalid environment variables found:", parsedEnv.error.flatten().fieldErrors);
|
|
169
|
+
}
|
|
170
|
+
// Consider throwing an error in production for critical misconfigurations.
|
|
171
|
+
}
|
|
172
|
+
const env = parsedEnv.success ? parsedEnv.data : EnvSchema.parse({});
|
|
173
|
+
// --- Directory Ensurance Function ---
|
|
174
|
+
/**
|
|
175
|
+
* Ensures a directory exists and is within the project root.
|
|
176
|
+
* @param dirPath The desired path for the directory (can be relative or absolute).
|
|
177
|
+
* @param rootDir The root directory of the project to contain the directory.
|
|
178
|
+
* @param dirName The name of the directory type for logging (e.g., "logs").
|
|
179
|
+
* @returns The validated, absolute path to the directory, or null if invalid.
|
|
180
|
+
*/
|
|
181
|
+
const ensureDirectory = (dirPath, rootDir, dirName) => {
|
|
182
|
+
const resolvedDirPath = path.isAbsolute(dirPath)
|
|
183
|
+
? dirPath
|
|
184
|
+
: path.resolve(rootDir, dirPath);
|
|
185
|
+
// Ensure the resolved path is within the project root boundary
|
|
186
|
+
if (!resolvedDirPath.startsWith(rootDir + path.sep) &&
|
|
187
|
+
resolvedDirPath !== rootDir) {
|
|
188
|
+
if (process.stdout.isTTY) {
|
|
189
|
+
console.error(`Error: ${dirName} path "${dirPath}" resolves to "${resolvedDirPath}", which is outside the project boundary "${rootDir}".`);
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
if (!existsSync(resolvedDirPath)) {
|
|
194
|
+
try {
|
|
195
|
+
mkdirSync(resolvedDirPath, { recursive: true });
|
|
196
|
+
if (process.stdout.isTTY) {
|
|
197
|
+
console.log(`Created ${dirName} directory: ${resolvedDirPath}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
202
|
+
if (process.stdout.isTTY) {
|
|
203
|
+
console.error(`Error creating ${dirName} directory at ${resolvedDirPath}: ${errorMessage}`);
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
try {
|
|
210
|
+
const stats = statSync(resolvedDirPath);
|
|
211
|
+
if (!stats.isDirectory()) {
|
|
212
|
+
if (process.stdout.isTTY) {
|
|
213
|
+
console.error(`Error: ${dirName} path ${resolvedDirPath} exists but is not a directory.`);
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch (statError) {
|
|
219
|
+
if (process.stdout.isTTY) {
|
|
220
|
+
console.error(`Error accessing ${dirName} path ${resolvedDirPath}: ${statError.message}`);
|
|
221
|
+
}
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return resolvedDirPath;
|
|
226
|
+
};
|
|
227
|
+
// --- End Directory Ensurance Function ---
|
|
228
|
+
// --- Logs Directory Handling ---
|
|
229
|
+
const validatedLogsPath = ensureDirectory(env.LOGS_DIR, projectRoot, "logs");
|
|
230
|
+
if (!validatedLogsPath) {
|
|
231
|
+
if (process.stdout.isTTY) {
|
|
232
|
+
console.error("FATAL: Logs directory configuration is invalid or could not be created. Please check permissions and path. Exiting.");
|
|
233
|
+
}
|
|
234
|
+
process.exit(1); // Exit if logs directory is not usable
|
|
235
|
+
}
|
|
236
|
+
// --- End Logs Directory Handling ---
|
|
237
|
+
/**
|
|
238
|
+
* Main application configuration object.
|
|
239
|
+
* Aggregates settings from validated environment variables and `package.json`.
|
|
240
|
+
*/
|
|
241
|
+
export const config = {
|
|
242
|
+
/** MCP server name. Env `MCP_SERVER_NAME` > `package.json` name > "mcp-ts-template". */
|
|
243
|
+
mcpServerName: env.MCP_SERVER_NAME || pkg.name,
|
|
244
|
+
/** MCP server version. Env `MCP_SERVER_VERSION` > `package.json` version > "0.0.0". */
|
|
245
|
+
mcpServerVersion: env.MCP_SERVER_VERSION || pkg.version,
|
|
246
|
+
/** Logging level. From `MCP_LOG_LEVEL` env var. Default: "debug". */
|
|
247
|
+
logLevel: env.MCP_LOG_LEVEL,
|
|
248
|
+
/** Absolute path to the logs directory. From `LOGS_DIR` env var. */
|
|
249
|
+
logsPath: validatedLogsPath,
|
|
250
|
+
/** Runtime environment. From `NODE_ENV` env var. Default: "development". */
|
|
251
|
+
environment: env.NODE_ENV,
|
|
252
|
+
/** MCP transport type ('stdio' or 'http'). From `MCP_TRANSPORT_TYPE` env var. Default: "stdio". */
|
|
253
|
+
mcpTransportType: env.MCP_TRANSPORT_TYPE,
|
|
254
|
+
/** HTTP server port (if http transport). From `MCP_HTTP_PORT` env var. Default: 3010. */
|
|
255
|
+
mcpHttpPort: env.MCP_HTTP_PORT,
|
|
256
|
+
/** HTTP server host (if http transport). From `MCP_HTTP_HOST` env var. Default: "127.0.0.1". */
|
|
257
|
+
mcpHttpHost: env.MCP_HTTP_HOST,
|
|
258
|
+
/** Array of allowed CORS origins (http transport). From `MCP_ALLOWED_ORIGINS` (comma-separated). */
|
|
259
|
+
mcpAllowedOrigins: env.MCP_ALLOWED_ORIGINS?.split(",")
|
|
260
|
+
.map((origin) => origin.trim())
|
|
261
|
+
.filter(Boolean),
|
|
262
|
+
/** Auth secret key (JWTs, http transport). From `MCP_AUTH_SECRET_KEY`. CRITICAL. */
|
|
263
|
+
mcpAuthSecretKey: env.MCP_AUTH_SECRET_KEY,
|
|
264
|
+
/** OpenRouter App URL. From `OPENROUTER_APP_URL`. Default: "http://localhost:3000". */
|
|
265
|
+
openrouterAppUrl: env.OPENROUTER_APP_URL || "http://localhost:3000",
|
|
266
|
+
/** OpenRouter App Name. From `OPENROUTER_APP_NAME`. Defaults to `mcpServerName`. */
|
|
267
|
+
openrouterAppName: env.OPENROUTER_APP_NAME || pkg.name || "MCP TS App",
|
|
268
|
+
/** OpenRouter API Key. From `OPENROUTER_API_KEY`. */
|
|
269
|
+
openrouterApiKey: env.OPENROUTER_API_KEY,
|
|
270
|
+
/** Default LLM model. From `LLM_DEFAULT_MODEL`. */
|
|
271
|
+
llmDefaultModel: env.LLM_DEFAULT_MODEL,
|
|
272
|
+
/** Default LLM temperature. From `LLM_DEFAULT_TEMPERATURE`. */
|
|
273
|
+
llmDefaultTemperature: env.LLM_DEFAULT_TEMPERATURE,
|
|
274
|
+
/** Default LLM top_p. From `LLM_DEFAULT_TOP_P`. */
|
|
275
|
+
llmDefaultTopP: env.LLM_DEFAULT_TOP_P,
|
|
276
|
+
/** Default LLM max tokens. From `LLM_DEFAULT_MAX_TOKENS`. */
|
|
277
|
+
llmDefaultMaxTokens: env.LLM_DEFAULT_MAX_TOKENS,
|
|
278
|
+
/** Default LLM top_k. From `LLM_DEFAULT_TOP_K`. */
|
|
279
|
+
llmDefaultTopK: env.LLM_DEFAULT_TOP_K,
|
|
280
|
+
/** Default LLM min_p. From `LLM_DEFAULT_MIN_P`. */
|
|
281
|
+
llmDefaultMinP: env.LLM_DEFAULT_MIN_P,
|
|
282
|
+
/** Gemini API Key. From `GEMINI_API_KEY`. */
|
|
283
|
+
geminiApiKey: env.GEMINI_API_KEY,
|
|
284
|
+
// NCBI Configuration
|
|
285
|
+
/** NCBI API Key. From `NCBI_API_KEY`. */
|
|
286
|
+
ncbiApiKey: env.NCBI_API_KEY,
|
|
287
|
+
/** NCBI Tool Identifier. From `NCBI_TOOL_IDENTIFIER`. Defaults to server name/version. */
|
|
288
|
+
ncbiToolIdentifier: env.NCBI_TOOL_IDENTIFIER ||
|
|
289
|
+
`${env.MCP_SERVER_NAME || pkg.name}/${env.MCP_SERVER_VERSION || pkg.version}`,
|
|
290
|
+
/** NCBI Admin Email. From `NCBI_ADMIN_EMAIL`. */
|
|
291
|
+
ncbiAdminEmail: env.NCBI_ADMIN_EMAIL,
|
|
292
|
+
/** NCBI Request Delay in MS. From `NCBI_REQUEST_DELAY_MS`. Dynamically set based on API key presence. */
|
|
293
|
+
ncbiRequestDelayMs: env.NCBI_REQUEST_DELAY_MS ?? (env.NCBI_API_KEY ? 100 : 334),
|
|
294
|
+
/** NCBI Max Retries. From `NCBI_MAX_RETRIES`. */
|
|
295
|
+
ncbiMaxRetries: env.NCBI_MAX_RETRIES,
|
|
296
|
+
/** OAuth Proxy configurations. Undefined if no related env vars are set. */
|
|
297
|
+
oauthProxy: env.OAUTH_PROXY_AUTHORIZATION_URL ||
|
|
298
|
+
env.OAUTH_PROXY_TOKEN_URL ||
|
|
299
|
+
env.OAUTH_PROXY_REVOCATION_URL ||
|
|
300
|
+
env.OAUTH_PROXY_ISSUER_URL ||
|
|
301
|
+
env.OAUTH_PROXY_SERVICE_DOCUMENTATION_URL ||
|
|
302
|
+
env.OAUTH_PROXY_DEFAULT_CLIENT_REDIRECT_URIS
|
|
303
|
+
? {
|
|
304
|
+
authorizationUrl: env.OAUTH_PROXY_AUTHORIZATION_URL,
|
|
305
|
+
tokenUrl: env.OAUTH_PROXY_TOKEN_URL,
|
|
306
|
+
revocationUrl: env.OAUTH_PROXY_REVOCATION_URL,
|
|
307
|
+
issuerUrl: env.OAUTH_PROXY_ISSUER_URL,
|
|
308
|
+
serviceDocumentationUrl: env.OAUTH_PROXY_SERVICE_DOCUMENTATION_URL,
|
|
309
|
+
defaultClientRedirectUris: env.OAUTH_PROXY_DEFAULT_CLIENT_REDIRECT_URIS?.split(",")
|
|
310
|
+
.map((uri) => uri.trim())
|
|
311
|
+
.filter(Boolean),
|
|
312
|
+
}
|
|
313
|
+
: undefined,
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* Configured logging level for the application.
|
|
317
|
+
* Exported for convenience.
|
|
318
|
+
*/
|
|
319
|
+
export const logLevel = config.logLevel;
|
|
320
|
+
/**
|
|
321
|
+
* Configured runtime environment ("development", "production", etc.).
|
|
322
|
+
* Exported for convenience.
|
|
323
|
+
*/
|
|
324
|
+
export const environment = config.environment;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Main entry point for the MCP TypeScript Template application.
|
|
4
|
+
* This script initializes the configuration, sets up the logger, starts the
|
|
5
|
+
* MCP server (either via STDIO or HTTP transport), and handles graceful
|
|
6
|
+
* shutdown on process signals or unhandled errors.
|
|
7
|
+
*
|
|
8
|
+
* The script uses an Immediately Invoked Function Expression (IIFE) with async/await
|
|
9
|
+
* to manage the asynchronous nature of server startup and shutdown.
|
|
10
|
+
*
|
|
11
|
+
* Key operations:
|
|
12
|
+
* 1. Import necessary modules and utilities.
|
|
13
|
+
* 2. Define a `shutdown` function for graceful server termination.
|
|
14
|
+
* 3. Define a `start` function to:
|
|
15
|
+
* - Initialize the logger with the configured log level.
|
|
16
|
+
* - Create a startup request context for logging and correlation.
|
|
17
|
+
* - Initialize and start the MCP server transport (stdio or http).
|
|
18
|
+
* - Set up global error handlers (uncaughtException, unhandledRejection)
|
|
19
|
+
* and signal handlers (SIGTERM, SIGINT) to trigger graceful shutdown.
|
|
20
|
+
* 4. Execute the `start` function within an async IIFE.
|
|
21
|
+
*
|
|
22
|
+
* @module src/index
|
|
23
|
+
*/
|
|
24
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Main entry point for the MCP TypeScript Template application.
|
|
4
|
+
* This script initializes the configuration, sets up the logger, starts the
|
|
5
|
+
* MCP server (either via STDIO or HTTP transport), and handles graceful
|
|
6
|
+
* shutdown on process signals or unhandled errors.
|
|
7
|
+
*
|
|
8
|
+
* The script uses an Immediately Invoked Function Expression (IIFE) with async/await
|
|
9
|
+
* to manage the asynchronous nature of server startup and shutdown.
|
|
10
|
+
*
|
|
11
|
+
* Key operations:
|
|
12
|
+
* 1. Import necessary modules and utilities.
|
|
13
|
+
* 2. Define a `shutdown` function for graceful server termination.
|
|
14
|
+
* 3. Define a `start` function to:
|
|
15
|
+
* - Initialize the logger with the configured log level.
|
|
16
|
+
* - Create a startup request context for logging and correlation.
|
|
17
|
+
* - Initialize and start the MCP server transport (stdio or http).
|
|
18
|
+
* - Set up global error handlers (uncaughtException, unhandledRejection)
|
|
19
|
+
* and signal handlers (SIGTERM, SIGINT) to trigger graceful shutdown.
|
|
20
|
+
* 4. Execute the `start` function within an async IIFE.
|
|
21
|
+
*
|
|
22
|
+
* @module src/index
|
|
23
|
+
*/
|
|
24
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
25
|
+
import { config, environment } from "./config/index.js";
|
|
26
|
+
import { initializeAndStartServer } from "./mcp-server/server.js";
|
|
27
|
+
import { requestContextService } from "./utils/index.js";
|
|
28
|
+
import { logger } from "./utils/internal/logger.js";
|
|
29
|
+
/**
|
|
30
|
+
* Holds the main MCP server instance, primarily for STDIO transport.
|
|
31
|
+
* For HTTP transport, server instances are typically managed per session.
|
|
32
|
+
* @private
|
|
33
|
+
*/
|
|
34
|
+
let server;
|
|
35
|
+
/**
|
|
36
|
+
* Gracefully shuts down the main MCP server and associated resources.
|
|
37
|
+
* Called on process termination signals or critical unhandled errors.
|
|
38
|
+
*
|
|
39
|
+
* @param signal - The signal or event name that triggered the shutdown.
|
|
40
|
+
* @returns A promise that resolves when shutdown is complete or an error occurs.
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
const shutdown = async (signal) => {
|
|
44
|
+
const shutdownContext = requestContextService.createRequestContext({
|
|
45
|
+
operation: "ServerShutdown",
|
|
46
|
+
triggerEvent: signal,
|
|
47
|
+
});
|
|
48
|
+
logger.info(`Received ${signal}. Initiating graceful shutdown...`, shutdownContext);
|
|
49
|
+
try {
|
|
50
|
+
if (server) {
|
|
51
|
+
logger.info("Attempting to close main MCP server...", shutdownContext);
|
|
52
|
+
await server.close();
|
|
53
|
+
logger.info("Main MCP server closed successfully.", shutdownContext);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
logger.notice("No global server instance found to close during shutdown (this may be normal for HTTP transport).", shutdownContext);
|
|
57
|
+
}
|
|
58
|
+
logger.info("Graceful shutdown completed successfully. Exiting.", shutdownContext);
|
|
59
|
+
process.exit(0);
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
logger.error("Critical error encountered during shutdown process.", {
|
|
63
|
+
...shutdownContext,
|
|
64
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
65
|
+
errorStack: error instanceof Error ? error.stack : undefined,
|
|
66
|
+
});
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Initializes and starts the main MCP server application.
|
|
72
|
+
* Orchestrates logger setup, server initialization, transport startup,
|
|
73
|
+
* and global error/signal handling.
|
|
74
|
+
*
|
|
75
|
+
* @returns A promise that resolves when the server has started and handlers are registered,
|
|
76
|
+
* or rejects if a critical startup error occurs.
|
|
77
|
+
* @private
|
|
78
|
+
*/
|
|
79
|
+
const start = async () => {
|
|
80
|
+
const validMcpLogLevels = [
|
|
81
|
+
"debug",
|
|
82
|
+
"info",
|
|
83
|
+
"notice",
|
|
84
|
+
"warning",
|
|
85
|
+
"error",
|
|
86
|
+
"crit",
|
|
87
|
+
"alert",
|
|
88
|
+
"emerg",
|
|
89
|
+
];
|
|
90
|
+
const initialLogLevelConfig = config.logLevel;
|
|
91
|
+
let validatedMcpLogLevel = "info";
|
|
92
|
+
if (validMcpLogLevels.includes(initialLogLevelConfig)) {
|
|
93
|
+
validatedMcpLogLevel = initialLogLevelConfig;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
if (process.stdout.isTTY) {
|
|
97
|
+
console.warn(`[Startup Warning] Invalid MCP_LOG_LEVEL "${initialLogLevelConfig}" found in configuration. ` +
|
|
98
|
+
`Defaulting to log level "info". Valid levels are: ${validMcpLogLevels.join(", ")}.`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
await logger.initialize(validatedMcpLogLevel);
|
|
102
|
+
logger.info(`Logger has been initialized by start(). Effective MCP logging level set to: ${validatedMcpLogLevel}.`);
|
|
103
|
+
// Configure RequestContextService once globally
|
|
104
|
+
requestContextService.configure({
|
|
105
|
+
appName: config.mcpServerName,
|
|
106
|
+
appVersion: config.mcpServerVersion,
|
|
107
|
+
environment,
|
|
108
|
+
});
|
|
109
|
+
logger.debug("RequestContextService configured with app name, version, and environment.");
|
|
110
|
+
const transportType = config.mcpTransportType;
|
|
111
|
+
const startupContext = requestContextService.createRequestContext({
|
|
112
|
+
operation: `ServerStartupSequence_${transportType}`,
|
|
113
|
+
applicationName: config.mcpServerName,
|
|
114
|
+
applicationVersion: config.mcpServerVersion,
|
|
115
|
+
nodeEnvironment: environment,
|
|
116
|
+
});
|
|
117
|
+
logger.debug("Application configuration loaded successfully.", {
|
|
118
|
+
...startupContext,
|
|
119
|
+
configSummary: {
|
|
120
|
+
serverName: config.mcpServerName,
|
|
121
|
+
serverVersion: config.mcpServerVersion,
|
|
122
|
+
transport: config.mcpTransportType,
|
|
123
|
+
logLevel: config.logLevel,
|
|
124
|
+
env: config.environment,
|
|
125
|
+
httpPort: config.mcpTransportType === "http" ? config.mcpHttpPort : undefined,
|
|
126
|
+
httpHost: config.mcpTransportType === "http" ? config.mcpHttpHost : undefined,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
logger.info(`Starting ${config.mcpServerName} (Version: ${config.mcpServerVersion}, Transport: ${transportType}, Env: ${environment})...`, startupContext);
|
|
130
|
+
try {
|
|
131
|
+
logger.debug("Calling initializeAndStartServer to set up MCP transport...", startupContext);
|
|
132
|
+
const potentialServerInstance = await initializeAndStartServer();
|
|
133
|
+
if (transportType === "stdio" &&
|
|
134
|
+
potentialServerInstance instanceof McpServer) {
|
|
135
|
+
server = potentialServerInstance;
|
|
136
|
+
logger.info("STDIO McpServer instance stored globally for shutdown.", startupContext);
|
|
137
|
+
}
|
|
138
|
+
else if (transportType === "http") {
|
|
139
|
+
logger.info("HTTP transport initialized. Server lifecycle managed by HTTP listener and session handlers.", startupContext);
|
|
140
|
+
}
|
|
141
|
+
logger.info(`${config.mcpServerName} is now running and ready to accept connections via ${transportType} transport.`, {
|
|
142
|
+
...startupContext,
|
|
143
|
+
serverStartTime: new Date().toISOString(),
|
|
144
|
+
});
|
|
145
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
146
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
147
|
+
process.on("uncaughtException", async (error) => {
|
|
148
|
+
const errorContext = {
|
|
149
|
+
...startupContext,
|
|
150
|
+
triggerEvent: "uncaughtException",
|
|
151
|
+
errorMessage: error.message,
|
|
152
|
+
errorStack: error.stack,
|
|
153
|
+
};
|
|
154
|
+
logger.error("FATAL: Uncaught exception detected. This indicates a bug or unexpected state. Initiating shutdown...", errorContext);
|
|
155
|
+
await shutdown("uncaughtException");
|
|
156
|
+
});
|
|
157
|
+
process.on("unhandledRejection", async (reason, promise) => {
|
|
158
|
+
const rejectionContext = {
|
|
159
|
+
...startupContext,
|
|
160
|
+
triggerEvent: "unhandledRejection",
|
|
161
|
+
rejectionReason: reason instanceof Error ? reason.message : String(reason),
|
|
162
|
+
rejectionStack: reason instanceof Error ? reason.stack : undefined,
|
|
163
|
+
};
|
|
164
|
+
logger.error("FATAL: Unhandled promise rejection detected. This indicates a bug or missing error handling in async code. Initiating shutdown...", rejectionContext);
|
|
165
|
+
await shutdown("unhandledRejection");
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
logger.error("CRITICAL ERROR DURING STARTUP: The application could not start. Exiting.", {
|
|
170
|
+
...startupContext,
|
|
171
|
+
finalErrorContext: "ApplicationStartupFailure",
|
|
172
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
173
|
+
errorStack: error instanceof Error ? error.stack : undefined,
|
|
174
|
+
});
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
// Async IIFE to allow top-level await for the start function.
|
|
179
|
+
(async () => {
|
|
180
|
+
try {
|
|
181
|
+
await start();
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
// This catch is a final fallback. `start()` should handle its errors and exit.
|
|
185
|
+
if (process.stdout.isTTY) {
|
|
186
|
+
console.error("[GLOBAL CATCH] An unexpected error occurred outside of the main start function's error handling:", error);
|
|
187
|
+
}
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
})();
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Defines the core logic, schemas, and types for the `echo` resource.
|
|
3
|
+
* This module includes a Zod schema for query parameter validation, type definitions,
|
|
4
|
+
* and the main processing function that constructs the resource response.
|
|
5
|
+
* The echo resource is designed to return a message, typically extracted from the
|
|
6
|
+
* request URI's path or query parameters, along with a timestamp.
|
|
7
|
+
* @module src/mcp-server/resources/echoResource/echoResourceLogic
|
|
8
|
+
*/
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
import { type RequestContext } from "../../../utils/index.js";
|
|
11
|
+
/**
|
|
12
|
+
* Zod schema defining expected query parameters for the echo resource.
|
|
13
|
+
*
|
|
14
|
+
* This schema is intended for validating parameters passed via the URI's query string
|
|
15
|
+
* (e.g., `echo://some_message?message=override_from_query&anotherParam=value`).
|
|
16
|
+
* Path parameters, such as `{message}` in a template like `echo://{message}`,
|
|
17
|
+
* are typically defined in the `ResourceTemplate` (see `registration.ts`) and
|
|
18
|
+
* extracted by the MCP SDK from the URI path. The SDK merges these path
|
|
19
|
+
* parameters into the `params` object passed to the handler.
|
|
20
|
+
*
|
|
21
|
+
* If a path parameter and a query parameter share the same name (e.g., 'message'),
|
|
22
|
+
* the query parameter will take precedence over the path parameter. This schema
|
|
23
|
+
* defines `message` as an optional query parameter.
|
|
24
|
+
*/
|
|
25
|
+
export declare const EchoResourceQuerySchema: z.ZodObject<{
|
|
26
|
+
/**
|
|
27
|
+
* Optional message to be echoed back in the response.
|
|
28
|
+
* If the resource template also defines a 'message' path parameter,
|
|
29
|
+
* this query parameter will override the path parameter's value if both are present.
|
|
30
|
+
*/
|
|
31
|
+
message: z.ZodOptional<z.ZodString>;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
message?: string | undefined;
|
|
34
|
+
}, {
|
|
35
|
+
message?: string | undefined;
|
|
36
|
+
}>;
|
|
37
|
+
/**
|
|
38
|
+
* TypeScript type inferred from the {@link EchoResourceQuerySchema}.
|
|
39
|
+
* Represents the validated query parameters that might be passed to the echo resource.
|
|
40
|
+
*/
|
|
41
|
+
export type EchoResourceParams = z.infer<typeof EchoResourceQuerySchema>;
|
|
42
|
+
/**
|
|
43
|
+
* Defines the structure of the JSON payload returned by the `processEchoResource` function.
|
|
44
|
+
* This object is typically JSON-stringified by the resource handler before being sent
|
|
45
|
+
* as the resource content.
|
|
46
|
+
*
|
|
47
|
+
* @property message - The message that is being echoed. This could be from a path parameter,
|
|
48
|
+
* a query parameter (which takes precedence), or a default value.
|
|
49
|
+
* @property timestamp - An ISO 8601 timestamp indicating when the response was generated.
|
|
50
|
+
* @property requestUri - The full URI of the original resource request.
|
|
51
|
+
*/
|
|
52
|
+
export interface EchoResourceResponsePayload {
|
|
53
|
+
/** The message that is being echoed. */
|
|
54
|
+
message: string;
|
|
55
|
+
/** An ISO 8601 timestamp indicating when the response was generated. */
|
|
56
|
+
timestamp: string;
|
|
57
|
+
/** The full URI of the original resource request. */
|
|
58
|
+
requestUri: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Processes the core logic for an echo resource request.
|
|
62
|
+
* It constructs a response payload containing a message (derived from path or query parameters),
|
|
63
|
+
* the current timestamp, and the original request URI.
|
|
64
|
+
*
|
|
65
|
+
* The `params` argument is expected to contain validated query parameters. If the resource
|
|
66
|
+
* template (e.g., `echo://{message}`) includes path parameters, the MCP SDK extracts
|
|
67
|
+
* them and merges them into the `params` object. If a query parameter shares the same
|
|
68
|
+
* name as a path parameter, the query parameter's value takes precedence. This function
|
|
69
|
+
* assumes `params.message` will hold the definitive message.
|
|
70
|
+
*
|
|
71
|
+
* @param uri - The full URL object of the incoming resource request.
|
|
72
|
+
* @param params - The validated query parameters for the request.
|
|
73
|
+
* This object also includes path parameters merged by the SDK, with query parameters
|
|
74
|
+
* taking precedence in case of name conflicts.
|
|
75
|
+
* @param context - The request context, used for logging and tracing the operation.
|
|
76
|
+
* @returns The data payload for the response.
|
|
77
|
+
* This payload is typically JSON-stringified by the calling handler.
|
|
78
|
+
*/
|
|
79
|
+
export declare const processEchoResource: (uri: URL, params: EchoResourceParams, context: RequestContext) => EchoResourceResponsePayload;
|