mcp-grocy 1.10.0 โ†’ 2.0.0

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 (44) hide show
  1. package/README.md +11 -11
  2. package/build/api/client.js +61 -94
  3. package/build/config/index.js +200 -0
  4. package/build/main.js +33 -18
  5. package/build/resources/README.md +11 -11
  6. package/build/resources/config.md +19 -155
  7. package/build/resources/examples.md +1 -1
  8. package/build/resources/installation.md +2 -2
  9. package/build/resources/response-format.md +2 -2
  10. package/build/server/http-server.js +189 -185
  11. package/build/server/mcp-server.js +91 -103
  12. package/build/tools/base.js +122 -37
  13. package/build/tools/household/definitions.js +157 -0
  14. package/build/tools/household/handlers.js +109 -0
  15. package/build/tools/household/index.js +25 -0
  16. package/build/tools/index.js +2 -494
  17. package/build/tools/inventory/definitions.js +379 -0
  18. package/build/tools/inventory/handlers.js +430 -0
  19. package/build/tools/inventory/index.js +32 -0
  20. package/build/tools/module-loader.js +146 -0
  21. package/build/tools/recipes/definitions.js +122 -52
  22. package/build/tools/recipes/handlers.js +309 -158
  23. package/build/tools/recipes/index.js +22 -11
  24. package/build/tools/recipes/validations.js +23 -0
  25. package/build/tools/shopping/definitions.js +71 -0
  26. package/build/tools/shopping/handlers.js +43 -0
  27. package/build/tools/shopping/index.js +9 -102
  28. package/build/tools/system/definitions.js +86 -0
  29. package/build/tools/system/handlers.js +94 -0
  30. package/build/tools/system/index.js +11 -225
  31. package/build/tools/validation-helpers.js +110 -0
  32. package/build/types/index.js +62 -0
  33. package/build/utils/errors.js +138 -0
  34. package/build/utils/logger.js +141 -0
  35. package/build/version.js +1 -1
  36. package/package.json +3 -1
  37. package/build/config/environment.js +0 -142
  38. package/build/resources/CHANGELOG.md +0 -352
  39. package/build/tools/products/definitions.js +0 -57
  40. package/build/tools/products/handlers.js +0 -78
  41. package/build/tools/products/index.js +0 -13
  42. package/build/tools/stock/definitions.js +0 -234
  43. package/build/tools/stock/handlers.js +0 -391
  44. package/build/tools/stock/index.js +0 -19
package/README.md CHANGED
@@ -63,7 +63,7 @@ Transform your LLM into an intelligent household management assistant with focus
63
63
 
64
64
  # Configure
65
65
  cp .env.example .env
66
- # Edit .env with your GROCY_BASE_URL and GROCY_APIKEY_VALUE
66
+ # Edit .env with your GROCY_BASE_URL and GROCY_API_KEY
67
67
 
68
68
  # Run
69
69
  docker compose up -d
@@ -74,7 +74,7 @@ Test with mock data (no real Grocy instance needed):
74
74
  ```bash
75
75
  # In .env file, any values work for mock mode
76
76
  GROCY_BASE_URL=http://mock
77
- GROCY_APIKEY_VALUE=mock
77
+ GROCY_API_KEY=mock
78
78
 
79
79
  npm install && npm run dev
80
80
  ```
@@ -93,7 +93,7 @@ npm run build
93
93
  ### Docker
94
94
 
95
95
  ```bash
96
- docker run -e GROCY_APIKEY_VALUE=your_api_key -e GROCY_BASE_URL=http://your-grocy-instance ghcr.io/miguelangel-nubla/mcp-grocy:latest
96
+ docker run -e GROCY_API_KEY=your_api_key -e GROCY_BASE_URL=http://your-grocy-instance ghcr.io/miguelangel-nubla/mcp-grocy:latest
97
97
  ```
98
98
 
99
99
  ### Docker Compose (Recommended)
@@ -126,20 +126,20 @@ docker compose up -d
126
126
  2. **Configure the server:**
127
127
  ```bash
128
128
  cp .env.example .env
129
- # Edit .env with your GROCY_BASE_URL and GROCY_APIKEY_VALUE
129
+ # Edit .env with your GROCY_BASE_URL and GROCY_API_KEY
130
130
  ```
131
131
 
132
132
  3. **Essential variables:**
133
133
  - `GROCY_BASE_URL` - Your Grocy instance URL
134
- - `GROCY_APIKEY_VALUE` - Your Grocy API key
134
+ - `GROCY_API_KEY` - Your Grocy API key
135
135
 
136
136
  ### Configuration Options
137
137
 
138
138
  | Method | Use Case | Command |
139
139
  |--------|----------|---------|
140
140
  | **`.env` file** | Recommended for most users | `cp .env.example .env` |
141
- | **Environment variables** | CI/CD, containers | `GROCY_BASE_URL=... GROCY_APIKEY_VALUE=... mcp-grocy` |
142
- | **Tool toggles** | Customize functionality | Edit `TOOL__*` variables in `.env` |
141
+ | **Environment variables** | CI/CD, containers | `GROCY_BASE_URL=... GROCY_API_KEY=... mcp-grocy` |
142
+ | **Tool configuration** | Customize functionality | Edit `tools` section in `mcp-grocy.yaml` |
143
143
 
144
144
  ๐Ÿ“– **For complete configuration reference:** See [Configuration Guide](src/resources/config.md)
145
145
 
@@ -172,7 +172,7 @@ npm start
172
172
  |----------|---------|-------------|
173
173
  | [๐Ÿ“– API Reference](src/resources/api-reference.md) | Complete tool documentation | Tool usage and examples |
174
174
  | [โš™๏ธ Configuration Guide](src/resources/config.md) | Advanced configuration reference | Detailed setup, presets, troubleshooting |
175
- | [๐Ÿ“‹ .env.example](.env.example) | Configuration template with ALL tools | Copy and customize for your setup |
175
+ | [๐Ÿ“‹ .env.example](.env.example) | Environment configuration template | Copy and customize for your setup |
176
176
  | [๐Ÿงช MCP Inspector](https://github.com/modelcontextprotocol/inspector) | Protocol debugging | Debug MCP interactions |
177
177
 
178
178
  ### ๐Ÿ†˜ Troubleshooting
@@ -185,17 +185,17 @@ npm start
185
185
  - For HTTPS URLs, ensure SSL certificate is valid or disable verification with `GROCY_ENABLE_SSL_VERIFY=false`
186
186
 
187
187
  **"Invalid API key" or "Authentication failed"**
188
- - Verify your `GROCY_APIKEY_VALUE` is correct
188
+ - Verify your `GROCY_API_KEY` is correct
189
189
  - Check that the API key exists in your Grocy instance (User Settings โ†’ API Keys)
190
190
  - Ensure the API key has proper permissions
191
191
 
192
192
  **"Tool not found" errors**
193
- - Check if the tool is enabled in your `.env` file (tool toggles)
193
+ - Check if the tool is enabled in your `mcp-grocy.yaml` file
194
194
  - Verify you're using the correct tool names from the API reference
195
195
 
196
196
  **Large response errors**
197
197
  - Increase `REST_RESPONSE_SIZE_LIMIT` if you have many products/stock entries
198
- - Consider using tool toggles to disable unused functionality
198
+ - Consider disabling unused tools in `mcp-grocy.yaml`
199
199
 
200
200
  #### Debug Mode
201
201
 
@@ -1,77 +1,64 @@
1
+ /**
2
+ * Simplified API client for Grocy
3
+ */
1
4
  import axios from 'axios';
2
5
  import https from 'https';
3
- import config from '../config/environment.js';
4
- export class ApiError extends Error {
5
- status;
6
- response;
7
- constructor(message, status, response) {
8
- super(message);
9
- this.name = 'ApiError';
10
- this.status = status;
11
- this.response = response;
12
- }
13
- }
6
+ import { config } from '../config/index.js';
7
+ import { logger } from '../utils/logger.js';
8
+ import { ApiError, ErrorHandler } from '../utils/errors.js';
14
9
  export class GrocyApiClient {
15
10
  axiosInstance;
16
11
  API_KEY_HEADER = 'GROCY-API-KEY';
17
12
  constructor() {
18
- const { GROCY_ENABLE_SSL_VERIFY, GROCY_APIKEY_VALUE } = config.get();
19
- this.axiosInstance = axios.create({
20
- baseURL: config.getGrocyBaseUrl(),
21
- validateStatus: () => true, // Allow any status code
22
- timeout: 30000, // 30 seconds timeout
23
- httpsAgent: GROCY_ENABLE_SSL_VERIFY ? undefined : new https.Agent({
13
+ this.axiosInstance = this.createAxiosInstance();
14
+ this.setupInterceptors();
15
+ }
16
+ createAxiosInstance() {
17
+ const instance = axios.create({
18
+ baseURL: config.grocy.base_url,
19
+ validateStatus: () => true, // Handle all status codes manually
20
+ timeout: 30000,
21
+ httpsAgent: config.grocy.enable_ssl_verify ? undefined : new https.Agent({
24
22
  rejectUnauthorized: false
25
23
  })
26
24
  });
27
- // Set default authentication if available
28
- if (GROCY_APIKEY_VALUE) {
29
- this.axiosInstance.defaults.headers.common[this.API_KEY_HEADER] = GROCY_APIKEY_VALUE;
25
+ // Set default authentication
26
+ if (config.grocy.api_key) {
27
+ instance.defaults.headers.common[this.API_KEY_HEADER] = config.grocy.api_key;
30
28
  }
31
- // Add request interceptor for logging
29
+ return instance;
30
+ }
31
+ setupInterceptors() {
32
+ // Request logging
32
33
  this.axiosInstance.interceptors.request.use((config) => {
33
- console.error(`[API] ${config.method?.toUpperCase()} ${config.url}`);
34
- if (config.data) {
35
- console.error(`[API] Request body: ${JSON.stringify(config.data)}`);
36
- }
34
+ logger.api(`${config.method?.toUpperCase()} ${config.url}`);
37
35
  return config;
38
36
  }, (error) => {
39
- console.error('[API] Request error:', error);
37
+ logger.error('Request error', 'API', { error: error.message });
40
38
  return Promise.reject(error);
41
39
  });
42
- // Add response interceptor for error handling
40
+ // Response logging
43
41
  this.axiosInstance.interceptors.response.use((response) => {
44
42
  if (response.status >= 400) {
45
- console.error(`[API] Error response (${response.status}): ${JSON.stringify(response.data)}`);
43
+ logger.warn(`HTTP ${response.status}`, 'API', {
44
+ url: response.config?.url,
45
+ status: response.status
46
+ });
46
47
  }
47
48
  return response;
48
49
  }, (error) => {
49
- console.error('[API] Response error:', error);
50
+ logger.error('Response error', 'API', { error: error.message });
50
51
  return Promise.reject(error);
51
52
  });
52
53
  }
53
54
  normalizeEndpoint(endpoint) {
54
- // Standardize path handling
55
- let normalizedEndpoint = endpoint;
56
- // Check if endpoint explicitly starts with /api/ - use it as is
57
- if (endpoint.startsWith('/api/')) {
58
- normalizedEndpoint = endpoint;
59
- }
60
- // Handle endpoints that start with api/ without leading slash
61
- else if (endpoint.startsWith('api/')) {
62
- normalizedEndpoint = `/${endpoint}`;
63
- }
64
- // All other endpoints - ensure they start with /api/
65
- else {
66
- if (endpoint.startsWith('/')) {
67
- normalizedEndpoint = `/api${endpoint}`;
68
- }
69
- else {
70
- normalizedEndpoint = `/api/${endpoint}`;
71
- }
72
- }
73
- console.error(`[API] Normalized endpoint: ${normalizedEndpoint}`);
74
- return normalizedEndpoint;
55
+ if (endpoint.startsWith('/api/'))
56
+ return endpoint;
57
+ if (endpoint.startsWith('api/'))
58
+ return `/${endpoint}`;
59
+ if (endpoint.startsWith('/'))
60
+ return `/api${endpoint}`;
61
+ return `/api/${endpoint}`;
75
62
  }
76
63
  buildQueryString(params) {
77
64
  return Object.entries(params)
@@ -80,57 +67,35 @@ export class GrocyApiClient {
80
67
  }
81
68
  async request(endpoint, options = {}) {
82
69
  const { method = 'GET', body = null, headers = {}, queryParams = {}, timeout } = options;
83
- let url = this.normalizeEndpoint(endpoint);
84
- // Add query parameters
85
- if (Object.keys(queryParams).length > 0) {
86
- const queryString = this.buildQueryString(queryParams);
87
- url += `?${queryString}`;
88
- }
89
- const requestConfig = {
90
- method,
91
- url,
92
- headers: {
93
- 'Accept': 'application/json',
94
- 'Content-Type': 'application/json',
95
- ...config.getCustomHeaders(),
96
- ...headers
97
- },
98
- timeout
99
- };
100
- if (['POST', 'PUT', 'PATCH'].includes(method) && body !== null) {
101
- requestConfig.data = body;
102
- }
103
- try {
70
+ return ErrorHandler.handleAsync(async () => {
71
+ let url = this.normalizeEndpoint(endpoint);
72
+ if (Object.keys(queryParams).length > 0) {
73
+ url += `?${this.buildQueryString(queryParams)}`;
74
+ }
75
+ const requestConfig = {
76
+ method,
77
+ url,
78
+ headers: {
79
+ 'Accept': 'application/json',
80
+ 'Content-Type': 'application/json',
81
+ ...config.getCustomHeaders(),
82
+ ...headers
83
+ },
84
+ ...(timeout && { timeout })
85
+ };
86
+ if (['POST', 'PUT', 'PATCH'].includes(method) && body !== null) {
87
+ requestConfig.data = body;
88
+ }
104
89
  const response = await this.axiosInstance.request(requestConfig);
105
90
  if (response.status >= 400) {
106
- throw new ApiError(`API error (${response.status}): ${JSON.stringify(response.data)}`, response.status, response.data);
91
+ throw new ApiError(response.data?.message || `HTTP ${response.status} error`, response.status, `${method} ${url}`, { responseData: response.data });
107
92
  }
108
93
  return {
109
94
  data: response.data,
110
95
  status: response.status,
111
96
  headers: response.headers
112
97
  };
113
- }
114
- catch (error) {
115
- if (axios.isAxiosError(error)) {
116
- const axiosError = error;
117
- if (axiosError.code === 'ECONNABORTED') {
118
- throw new ApiError('Connection timeout: The server took too long to respond');
119
- }
120
- else if (axiosError.code === 'ECONNRESET' || axiosError.message.includes('socket hang up')) {
121
- throw new ApiError('Connection reset: The server unexpectedly closed the connection');
122
- }
123
- else if (!axiosError.response) {
124
- throw new ApiError('Network error: Unable to reach the Grocy server');
125
- }
126
- }
127
- // Re-throw ApiError instances
128
- if (error instanceof ApiError) {
129
- throw error;
130
- }
131
- // Wrap other errors
132
- throw new ApiError(`Request failed: ${error.message || error}`);
133
- }
98
+ }, `API ${method} ${endpoint}`);
134
99
  }
135
100
  // Convenience methods
136
101
  async get(endpoint, options = {}) {
@@ -149,6 +114,8 @@ export class GrocyApiClient {
149
114
  return this.request(endpoint, { ...options, method: 'PATCH', body });
150
115
  }
151
116
  }
152
- // Export a singleton instance
117
+ // Export singleton instance
153
118
  export const apiClient = new GrocyApiClient();
154
119
  export default apiClient;
120
+ // Re-export ApiError for convenience
121
+ export { ApiError };
@@ -0,0 +1,200 @@
1
+ /**
2
+ * Unified configuration system
3
+ * Combines environment variables and YAML configuration
4
+ */
5
+ import { z } from 'zod';
6
+ import { readFileSync, existsSync } from 'fs';
7
+ import { resolve, dirname } from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import YAML from 'yaml';
10
+ import { logger } from '../utils/logger.js';
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ // Environment schema
13
+ const EnvironmentSchema = z.object({
14
+ // Grocy Configuration
15
+ GROCY_BASE_URL: z.string().url().optional(),
16
+ GROCY_API_KEY: z.string().optional(),
17
+ GROCY_ENABLE_SSL_VERIFY: z.enum(['true', 'false']).optional(),
18
+ // Server Configuration
19
+ REST_RESPONSE_SIZE_LIMIT: z.string().regex(/^\d+$/).optional(),
20
+ ENABLE_HTTP_SERVER: z.enum(['true', 'false']).optional(),
21
+ HTTP_SERVER_PORT: z.string().regex(/^\d+$/).optional(),
22
+ // Logging Configuration
23
+ LOG_LEVEL: z.enum(['DEBUG', 'INFO', 'WARN', 'ERROR']).optional(),
24
+ LOG_CATEGORIES: z.string().optional(),
25
+ // Build Configuration
26
+ RELEASE_VERSION: z.string().optional(),
27
+ NODE_ENV: z.enum(['development', 'production', 'test']).optional(),
28
+ });
29
+ // YAML configuration schema
30
+ const YamlConfigSchema = z.object({
31
+ server: z.object({
32
+ enable_http_server: z.boolean().default(false),
33
+ http_server_port: z.number().min(1).max(65535).default(8080),
34
+ }).default({}),
35
+ grocy: z.object({
36
+ base_url: z.string().url().default('http://localhost:9283'),
37
+ api_key: z.string().optional(),
38
+ enable_ssl_verify: z.boolean().default(true),
39
+ response_size_limit: z.number().positive().default(10000),
40
+ }).default({}),
41
+ tools: z.record(z.string(), z.object({
42
+ enabled: z.boolean().default(false),
43
+ ack_token: z.string().optional(),
44
+ }).catchall(z.unknown())).default({}),
45
+ });
46
+ export class ConfigManager {
47
+ static instance;
48
+ config;
49
+ // Unified config properties - final resolved values
50
+ grocy;
51
+ server;
52
+ tools;
53
+ constructor(configPath) {
54
+ this.config = this.loadConfig(configPath);
55
+ // Expose final resolved values
56
+ this.grocy = {
57
+ base_url: this.config.yaml.grocy.base_url,
58
+ ...(this.config.yaml.grocy.api_key !== undefined && { api_key: this.config.yaml.grocy.api_key }),
59
+ enable_ssl_verify: this.config.yaml.grocy.enable_ssl_verify,
60
+ response_size_limit: this.config.yaml.grocy.response_size_limit
61
+ };
62
+ this.server = {
63
+ enable_http_server: this.config.yaml.server.enable_http_server,
64
+ http_server_port: this.config.yaml.server.http_server_port
65
+ };
66
+ this.tools = this.config.yaml.tools;
67
+ }
68
+ static getInstance() {
69
+ if (!ConfigManager.instance) {
70
+ ConfigManager.instance = new ConfigManager();
71
+ }
72
+ return ConfigManager.instance;
73
+ }
74
+ loadConfig(configPath) {
75
+ // Load environment variables
76
+ const env = this.loadEnvironment();
77
+ // Load YAML configuration
78
+ const yaml = this.loadYamlConfig(configPath);
79
+ // Apply environment variable overrides
80
+ this.applyEnvironmentOverrides(yaml, env);
81
+ return { env, yaml };
82
+ }
83
+ loadEnvironment() {
84
+ try {
85
+ return EnvironmentSchema.parse(process.env);
86
+ }
87
+ catch (error) {
88
+ if (error instanceof z.ZodError) {
89
+ logger.error('Invalid environment variables', 'CONFIG');
90
+ error.errors.forEach(err => {
91
+ logger.error(`${err.path.join('.')}: ${err.message}`, 'CONFIG');
92
+ });
93
+ process.exit(1);
94
+ }
95
+ throw error;
96
+ }
97
+ }
98
+ loadYamlConfig(configPath) {
99
+ const yamlPath = this.findConfigFile(configPath);
100
+ try {
101
+ let configData = {};
102
+ if (existsSync(yamlPath)) {
103
+ const yamlContent = readFileSync(yamlPath, 'utf8');
104
+ configData = YAML.parse(yamlContent) || {};
105
+ logger.config(`Loaded YAML config from: ${yamlPath}`);
106
+ }
107
+ else {
108
+ logger.config('No YAML config found, using defaults');
109
+ }
110
+ return YamlConfigSchema.parse(configData);
111
+ }
112
+ catch (error) {
113
+ if (error instanceof z.ZodError) {
114
+ logger.error('Invalid YAML configuration', 'CONFIG');
115
+ error.errors.forEach(err => {
116
+ logger.error(`${err.path.join('.')}: ${err.message}`, 'CONFIG');
117
+ });
118
+ process.exit(1);
119
+ }
120
+ throw error;
121
+ }
122
+ }
123
+ findConfigFile(configPath) {
124
+ if (configPath)
125
+ return configPath;
126
+ // Look for config files in the following order:
127
+ // 1. Current working directory (for development)
128
+ // 2. Project root (relative to the compiled main.js)
129
+ const projectRoot = resolve(__dirname, '../..');
130
+ const possiblePaths = [
131
+ resolve(process.cwd(), 'mcp-grocy.yaml'),
132
+ resolve(process.cwd(), 'mcp-grocy.yml'),
133
+ resolve(projectRoot, 'mcp-grocy.yaml'),
134
+ resolve(projectRoot, 'mcp-grocy.yml'),
135
+ ];
136
+ return possiblePaths.find(path => existsSync(path)) ?? possiblePaths[0];
137
+ }
138
+ // Public getters
139
+ getConfig() {
140
+ return this.config;
141
+ }
142
+ getApiUrl() {
143
+ return this.grocy.base_url.endsWith('/') ? `${this.grocy.base_url}api` : `${this.grocy.base_url}/api`;
144
+ }
145
+ getCustomHeaders() {
146
+ const headers = {};
147
+ if (this.grocy.api_key) {
148
+ headers['GROCY-API-KEY'] = this.grocy.api_key;
149
+ }
150
+ return headers;
151
+ }
152
+ /**
153
+ * Apply environment variable overrides to YAML configuration
154
+ */
155
+ applyEnvironmentOverrides(yaml, env) {
156
+ // Grocy configuration overrides
157
+ if (env.GROCY_BASE_URL) {
158
+ yaml.grocy.base_url = env.GROCY_BASE_URL;
159
+ }
160
+ if (env.GROCY_API_KEY) {
161
+ yaml.grocy.api_key = env.GROCY_API_KEY;
162
+ }
163
+ if (env.GROCY_ENABLE_SSL_VERIFY !== undefined) {
164
+ yaml.grocy.enable_ssl_verify = env.GROCY_ENABLE_SSL_VERIFY === 'true';
165
+ }
166
+ if (env.REST_RESPONSE_SIZE_LIMIT !== undefined) {
167
+ yaml.grocy.response_size_limit = parseInt(env.REST_RESPONSE_SIZE_LIMIT, 10);
168
+ }
169
+ // Server configuration overrides
170
+ if (env.ENABLE_HTTP_SERVER !== undefined) {
171
+ yaml.server.enable_http_server = env.ENABLE_HTTP_SERVER === 'true';
172
+ }
173
+ if (env.HTTP_SERVER_PORT !== undefined) {
174
+ yaml.server.http_server_port = parseInt(env.HTTP_SERVER_PORT, 10);
175
+ }
176
+ }
177
+ parseToolConfiguration() {
178
+ const enabledTools = new Set();
179
+ const toolSubConfigs = new Map();
180
+ for (const [toolName, toolConfig] of Object.entries(this.config.yaml.tools)) {
181
+ if (toolConfig.enabled) {
182
+ enabledTools.add(toolName);
183
+ // Extract sub-configs (everything except standard fields)
184
+ const subConfigs = new Map();
185
+ for (const [key, value] of Object.entries(toolConfig)) {
186
+ if (!['enabled', 'ack_token'].includes(key)) {
187
+ subConfigs.set(key, value);
188
+ }
189
+ }
190
+ if (subConfigs.size > 0) {
191
+ toolSubConfigs.set(toolName, subConfigs);
192
+ }
193
+ }
194
+ }
195
+ return { enabledTools, toolSubConfigs };
196
+ }
197
+ }
198
+ // Export singleton instance
199
+ export const config = ConfigManager.getInstance();
200
+ export default config;
package/build/main.js CHANGED
@@ -1,29 +1,44 @@
1
1
  #!/usr/bin/env node
2
- // Load environment variables from .env file
2
+ /**
3
+ * Simplified main entry point
4
+ * Demonstrates the refactored architecture
5
+ */
6
+ // Load environment variables
3
7
  import 'dotenv/config';
4
8
  import { GrocyMcpServer } from './server/mcp-server.js';
5
- import config from './config/environment.js';
9
+ import { config } from './config/index.js';
6
10
  import { VERSION, PACKAGE_NAME as SERVER_NAME } from './version.js';
7
- // Debug output to help identify version and naming issues
8
- console.error(`Starting ${SERVER_NAME} server version ${VERSION}`);
11
+ import { logger } from './utils/logger.js';
12
+ import { ErrorHandler } from './utils/errors.js';
13
+ // Startup banner
14
+ logger.info(`Starting ${SERVER_NAME} v${VERSION}`, 'SERVER');
9
15
  async function main() {
10
- try {
11
- // Validate configuration early
12
- const envConfig = config.get();
13
- // Ensure required environment variables
14
- if (!config.hasApiKeyAuth()) {
15
- console.error('[WARNING] No GROCY_APIKEY_VALUE configured. Some API calls may fail.');
16
+ return ErrorHandler.handleAsync(async () => {
17
+ // Check API key
18
+ if (!config.grocy.api_key) {
19
+ logger.warn('No API key configured. Some operations may fail.', 'CONFIG');
16
20
  }
17
- // Create and start the server
18
- const server = new GrocyMcpServer();
21
+ // Log configuration summary
22
+ logger.config(`Grocy URL: ${config.grocy.base_url}`);
23
+ logger.config(`SSL Verify: ${config.grocy.enable_ssl_verify}`);
24
+ logger.config(`HTTP Server: ${config.server.enable_http_server}`);
25
+ // Create and start server
26
+ const server = await GrocyMcpServer.create();
19
27
  await server.start();
20
- }
21
- catch (error) {
22
- console.error('[ERROR] Failed to start server:', error);
23
- process.exit(1);
24
- }
28
+ logger.info('Server started successfully', 'SERVER');
29
+ }, 'server startup');
25
30
  }
31
+ // Error handling
32
+ process.on('uncaughtException', (error) => {
33
+ logger.error('Uncaught exception', 'PROCESS', { error });
34
+ process.exit(1);
35
+ });
36
+ process.on('unhandledRejection', (reason, promise) => {
37
+ logger.error('Unhandled rejection', 'PROCESS', { reason, promise });
38
+ process.exit(1);
39
+ });
40
+ // Start the application
26
41
  main().catch((error) => {
27
- console.error('[FATAL] Unhandled error:', error);
42
+ logger.error('Failed to start server', 'SERVER', { error });
28
43
  process.exit(1);
29
44
  });
@@ -63,7 +63,7 @@ Transform your LLM into an intelligent household management assistant with focus
63
63
 
64
64
  # Configure
65
65
  cp .env.example .env
66
- # Edit .env with your GROCY_BASE_URL and GROCY_APIKEY_VALUE
66
+ # Edit .env with your GROCY_BASE_URL and GROCY_API_KEY
67
67
 
68
68
  # Run
69
69
  docker compose up -d
@@ -74,7 +74,7 @@ Test with mock data (no real Grocy instance needed):
74
74
  ```bash
75
75
  # In .env file, any values work for mock mode
76
76
  GROCY_BASE_URL=http://mock
77
- GROCY_APIKEY_VALUE=mock
77
+ GROCY_API_KEY=mock
78
78
 
79
79
  npm install && npm run dev
80
80
  ```
@@ -93,7 +93,7 @@ npm run build
93
93
  ### Docker
94
94
 
95
95
  ```bash
96
- docker run -e GROCY_APIKEY_VALUE=your_api_key -e GROCY_BASE_URL=http://your-grocy-instance ghcr.io/miguelangel-nubla/mcp-grocy:latest
96
+ docker run -e GROCY_API_KEY=your_api_key -e GROCY_BASE_URL=http://your-grocy-instance ghcr.io/miguelangel-nubla/mcp-grocy:latest
97
97
  ```
98
98
 
99
99
  ### Docker Compose (Recommended)
@@ -126,20 +126,20 @@ docker compose up -d
126
126
  2. **Configure the server:**
127
127
  ```bash
128
128
  cp .env.example .env
129
- # Edit .env with your GROCY_BASE_URL and GROCY_APIKEY_VALUE
129
+ # Edit .env with your GROCY_BASE_URL and GROCY_API_KEY
130
130
  ```
131
131
 
132
132
  3. **Essential variables:**
133
133
  - `GROCY_BASE_URL` - Your Grocy instance URL
134
- - `GROCY_APIKEY_VALUE` - Your Grocy API key
134
+ - `GROCY_API_KEY` - Your Grocy API key
135
135
 
136
136
  ### Configuration Options
137
137
 
138
138
  | Method | Use Case | Command |
139
139
  |--------|----------|---------|
140
140
  | **`.env` file** | Recommended for most users | `cp .env.example .env` |
141
- | **Environment variables** | CI/CD, containers | `GROCY_BASE_URL=... GROCY_APIKEY_VALUE=... mcp-grocy` |
142
- | **Tool toggles** | Customize functionality | Edit `TOOL__*` variables in `.env` |
141
+ | **Environment variables** | CI/CD, containers | `GROCY_BASE_URL=... GROCY_API_KEY=... mcp-grocy` |
142
+ | **Tool configuration** | Customize functionality | Edit `tools` section in `mcp-grocy.yaml` |
143
143
 
144
144
  ๐Ÿ“– **For complete configuration reference:** See [Configuration Guide](src/resources/config.md)
145
145
 
@@ -172,7 +172,7 @@ npm start
172
172
  |----------|---------|-------------|
173
173
  | [๐Ÿ“– API Reference](src/resources/api-reference.md) | Complete tool documentation | Tool usage and examples |
174
174
  | [โš™๏ธ Configuration Guide](src/resources/config.md) | Advanced configuration reference | Detailed setup, presets, troubleshooting |
175
- | [๐Ÿ“‹ .env.example](.env.example) | Configuration template with ALL tools | Copy and customize for your setup |
175
+ | [๐Ÿ“‹ .env.example](.env.example) | Environment configuration template | Copy and customize for your setup |
176
176
  | [๐Ÿงช MCP Inspector](https://github.com/modelcontextprotocol/inspector) | Protocol debugging | Debug MCP interactions |
177
177
 
178
178
  ### ๐Ÿ†˜ Troubleshooting
@@ -185,17 +185,17 @@ npm start
185
185
  - For HTTPS URLs, ensure SSL certificate is valid or disable verification with `GROCY_ENABLE_SSL_VERIFY=false`
186
186
 
187
187
  **"Invalid API key" or "Authentication failed"**
188
- - Verify your `GROCY_APIKEY_VALUE` is correct
188
+ - Verify your `GROCY_API_KEY` is correct
189
189
  - Check that the API key exists in your Grocy instance (User Settings โ†’ API Keys)
190
190
  - Ensure the API key has proper permissions
191
191
 
192
192
  **"Tool not found" errors**
193
- - Check if the tool is enabled in your `.env` file (tool toggles)
193
+ - Check if the tool is enabled in your `mcp-grocy.yaml` file
194
194
  - Verify you're using the correct tool names from the API reference
195
195
 
196
196
  **Large response errors**
197
197
  - Increase `REST_RESPONSE_SIZE_LIMIT` if you have many products/stock entries
198
- - Consider using tool toggles to disable unused functionality
198
+ - Consider disabling unused tools in `mcp-grocy.yaml`
199
199
 
200
200
  #### Debug Mode
201
201