@aashari/boilerplate-mcp-server 1.15.0 → 1.16.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.
- package/CHANGELOG.md +12 -0
- package/README.md +138 -17
- package/STYLE_GUIDE.md +60 -1
- package/dist/resources/ipaddress.resource.d.ts +1 -0
- package/dist/resources/ipaddress.resource.js +14 -10
- package/dist/services/vendor.ip-api.com.types.d.ts +1 -43
- package/dist/tools/ipaddress.tool.d.ts +1 -0
- package/dist/tools/ipaddress.tool.js +20 -13
- package/dist/tools/ipaddress.types.d.ts +9 -13
- package/dist/utils/constants.util.d.ts +1 -1
- package/dist/utils/constants.util.js +1 -1
- package/dist/utils/transport.util.js +0 -1
- package/package.json +19 -19
- package/package.json.bak +19 -19
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# [1.16.0](https://github.com/aashari/boilerplate-mcp-server/compare/v1.15.0...v1.16.0) (2025-12-01)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* regenerate package-lock.json to fix CI dependency resolution ([a0225a8](https://github.com/aashari/boilerplate-mcp-server/commit/a0225a8f9bb0bb5b27a436099d0b131fa47e8cbc))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* modernize SDK usage and update dependencies ([#127](https://github.com/aashari/boilerplate-mcp-server/issues/127)) ([a36c9f6](https://github.com/aashari/boilerplate-mcp-server/commit/a36c9f644d842e9c5360d4ed2f207ada18d97ebd))
|
|
12
|
+
|
|
1
13
|
# [1.15.0](https://github.com/aashari/boilerplate-mcp-server/compare/v1.14.0...v1.15.0) (2025-12-01)
|
|
2
14
|
|
|
3
15
|
|
package/README.md
CHANGED
|
@@ -9,7 +9,10 @@ A production-ready foundation for developing custom Model Context Protocol (MCP)
|
|
|
9
9
|
|
|
10
10
|
- **Dual Transport Support**: STDIO and Streamable HTTP transports with automatic fallback
|
|
11
11
|
- **5-Layer Architecture**: Clean separation between CLI, tools, controllers, services, and utilities
|
|
12
|
-
- **Type Safety**: Full TypeScript implementation with Zod schema validation
|
|
12
|
+
- **Type Safety**: Full TypeScript implementation with Zod v4 schema validation
|
|
13
|
+
- **TOON Output Format**: Token-Oriented Object Notation for 30-60% fewer tokens than JSON
|
|
14
|
+
- **JMESPath Filtering**: Extract only needed fields from responses to reduce token costs
|
|
15
|
+
- **Modern SDK**: Uses MCP SDK v1.23.0 with `registerTool` API pattern
|
|
13
16
|
- **Complete IP Address Example**: Tools, resources, and CLI commands for IP geolocation
|
|
14
17
|
- **Comprehensive Testing**: Unit and integration tests with coverage reporting
|
|
15
18
|
- **Production Tooling**: ESLint, Prettier, semantic-release, and MCP Inspector integration
|
|
@@ -43,6 +46,8 @@ npm run build
|
|
|
43
46
|
npm run cli -- get-ip-details 8.8.8.8
|
|
44
47
|
npm run cli -- get-ip-details # Get your current IP
|
|
45
48
|
npm run cli -- get-ip-details 1.1.1.1 --include-extended-data
|
|
49
|
+
npm run cli -- get-ip-details 8.8.8.8 --jq "{ip: query, country: country}" # JQ filter
|
|
50
|
+
npm run cli -- get-ip-details 8.8.8.8 --output-format json # JSON output
|
|
46
51
|
|
|
47
52
|
# 2. STDIO Transport - For AI assistant integration (Claude Desktop, Cursor)
|
|
48
53
|
npm run mcp:stdio
|
|
@@ -69,6 +74,52 @@ npm run mcp:inspect # Auto-opens browser with debugging
|
|
|
69
74
|
- Health Check: `http://localhost:3000/` → Returns server version
|
|
70
75
|
- Run with: `TRANSPORT_MODE=http node dist/index.js`
|
|
71
76
|
|
|
77
|
+
## Output Formats
|
|
78
|
+
|
|
79
|
+
### TOON Format (Default)
|
|
80
|
+
|
|
81
|
+
TOON (Token-Oriented Object Notation) is a human-readable format optimized for LLMs, reducing token usage by 30-60% compared to JSON:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
status: success
|
|
85
|
+
query: 8.8.8.8
|
|
86
|
+
country: United States
|
|
87
|
+
city: Ashburn
|
|
88
|
+
lat: 39.03
|
|
89
|
+
lon: -77.5
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### JSON Format
|
|
93
|
+
|
|
94
|
+
Standard JSON output when `--output-format json` is specified:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"status": "success",
|
|
99
|
+
"query": "8.8.8.8",
|
|
100
|
+
"country": "United States",
|
|
101
|
+
"city": "Ashburn"
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### JMESPath Filtering
|
|
106
|
+
|
|
107
|
+
Use `--jq` to extract only needed fields, reducing token costs:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Extract specific fields
|
|
111
|
+
npm run cli -- get-ip-details 8.8.8.8 --jq "{ip: query, country: country}"
|
|
112
|
+
|
|
113
|
+
# Output:
|
|
114
|
+
# ip: 8.8.8.8
|
|
115
|
+
# country: United States
|
|
116
|
+
|
|
117
|
+
# Nested structure
|
|
118
|
+
npm run cli -- get-ip-details 8.8.8.8 --jq "{location: {city: city, coords: {lat: lat, lon: lon}}}"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
See [JMESPath documentation](https://jmespath.org) for more filter examples.
|
|
122
|
+
|
|
72
123
|
## Architecture Overview
|
|
73
124
|
|
|
74
125
|
<details>
|
|
@@ -99,6 +150,8 @@ src/
|
|
|
99
150
|
│ ├── config.util.ts # Environment configuration
|
|
100
151
|
│ ├── constants.util.ts # Version and package constants
|
|
101
152
|
│ ├── formatter.util.ts # Markdown formatting
|
|
153
|
+
│ ├── toon.util.ts # TOON format encoding
|
|
154
|
+
│ ├── jq.util.ts # JMESPath filtering
|
|
102
155
|
│ └── transport.util.ts # HTTP transport utilities
|
|
103
156
|
└── index.ts # Server entry point (dual transport)
|
|
104
157
|
```
|
|
@@ -126,9 +179,9 @@ The boilerplate follows a clean, layered architecture that promotes maintainabil
|
|
|
126
179
|
### 3. Resources Layer (`src/resources/`)
|
|
127
180
|
|
|
128
181
|
- **Purpose**: MCP resources providing contextual data accessible via URIs
|
|
129
|
-
- **Implementation**:
|
|
130
|
-
- **Example**: `ip://
|
|
131
|
-
- **Pattern**: Register URI
|
|
182
|
+
- **Implementation**: Uses `registerResource` API with `ResourceTemplate` for parameterized URIs
|
|
183
|
+
- **Example**: `ip://{ipAddress}` resource template providing IP geolocation data
|
|
184
|
+
- **Pattern**: Register URI template → Extract variables → Return formatted content
|
|
132
185
|
|
|
133
186
|
### 4. Controllers Layer (`src/controllers/`)
|
|
134
187
|
|
|
@@ -147,11 +200,13 @@ The boilerplate follows a clean, layered architecture that promotes maintainabil
|
|
|
147
200
|
### 6. Utils Layer (`src/utils/`)
|
|
148
201
|
|
|
149
202
|
- **Purpose**: Shared functionality across all layers
|
|
150
|
-
- **Key Components**:
|
|
203
|
+
- **Key Components**:
|
|
151
204
|
- `logger.util.ts`: Contextual logging (file:method context)
|
|
152
205
|
- `error.util.ts`: MCP-specific error formatting
|
|
153
206
|
- `transport.util.ts`: HTTP/API utilities with retry logic
|
|
154
207
|
- `config.util.ts`: Environment configuration management
|
|
208
|
+
- `toon.util.ts`: TOON format encoding (token-efficient output)
|
|
209
|
+
- `jq.util.ts`: JMESPath filtering for response transformation
|
|
155
210
|
|
|
156
211
|
## Developer Guide
|
|
157
212
|
|
|
@@ -396,16 +451,20 @@ async function handleGetData(args: Record<string, unknown>) {
|
|
|
396
451
|
}
|
|
397
452
|
}
|
|
398
453
|
|
|
399
|
-
// Registration function
|
|
454
|
+
// Registration function using the modern registerTool API (SDK v1.22.0+)
|
|
400
455
|
function registerTools(server: McpServer) {
|
|
401
456
|
const registerLogger = logger.forMethod('registerTools');
|
|
402
457
|
registerLogger.debug('Registering example tools...');
|
|
403
458
|
|
|
404
|
-
|
|
459
|
+
// SDK best practices: 'title' for UI display name, 'description' for detailed info
|
|
460
|
+
server.registerTool(
|
|
405
461
|
'example_get_data',
|
|
406
|
-
|
|
462
|
+
{
|
|
463
|
+
title: 'Get Example Data', // Display name for UI (e.g., 'Get Example Data')
|
|
464
|
+
description: `Gets data from the Example API with optional parameter.
|
|
407
465
|
Use this tool to fetch example data. Returns formatted data as Markdown.`,
|
|
408
|
-
|
|
466
|
+
inputSchema: GetDataSchema,
|
|
467
|
+
},
|
|
409
468
|
handleGetData
|
|
410
469
|
);
|
|
411
470
|
|
|
@@ -484,6 +543,63 @@ import exampleTools from './tools/example.tool.js';
|
|
|
484
543
|
exampleTools.registerTools(serverInstance);
|
|
485
544
|
```
|
|
486
545
|
|
|
546
|
+
### 6. Add MCP Resource (Optional)
|
|
547
|
+
|
|
548
|
+
Create a resource in `src/resources/` using the modern `registerResource` API:
|
|
549
|
+
|
|
550
|
+
```typescript
|
|
551
|
+
// src/resources/example.resource.ts
|
|
552
|
+
import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
553
|
+
import { Logger } from '../utils/logger.util.js';
|
|
554
|
+
import exampleController from '../controllers/example.controller.js';
|
|
555
|
+
import { formatErrorForMcpResource } from '../utils/error.util.js';
|
|
556
|
+
|
|
557
|
+
const logger = Logger.forContext('resources/example.resource.ts');
|
|
558
|
+
|
|
559
|
+
function registerResources(server: McpServer) {
|
|
560
|
+
const registerLogger = logger.forMethod('registerResources');
|
|
561
|
+
registerLogger.debug('Registering example resources...');
|
|
562
|
+
|
|
563
|
+
// Use registerResource with ResourceTemplate for parameterized URIs (SDK v1.22.0+)
|
|
564
|
+
server.registerResource(
|
|
565
|
+
'example-data',
|
|
566
|
+
new ResourceTemplate('example://{param}', { list: undefined }),
|
|
567
|
+
{
|
|
568
|
+
title: 'Example Data', // Display name for UI
|
|
569
|
+
description: 'Retrieve example data by parameter'
|
|
570
|
+
},
|
|
571
|
+
async (uri, variables) => {
|
|
572
|
+
const methodLogger = logger.forMethod('exampleResource');
|
|
573
|
+
try {
|
|
574
|
+
// Extract parameter from template variables
|
|
575
|
+
const param = variables.param as string | undefined;
|
|
576
|
+
|
|
577
|
+
methodLogger.debug('Example resource called', { uri: uri.href, param });
|
|
578
|
+
|
|
579
|
+
const result = await exampleController.getData({ param });
|
|
580
|
+
|
|
581
|
+
return {
|
|
582
|
+
contents: [
|
|
583
|
+
{
|
|
584
|
+
uri: uri.href,
|
|
585
|
+
text: result.content,
|
|
586
|
+
mimeType: 'text/markdown'
|
|
587
|
+
}
|
|
588
|
+
]
|
|
589
|
+
};
|
|
590
|
+
} catch (error) {
|
|
591
|
+
methodLogger.error('Resource error', error);
|
|
592
|
+
return formatErrorForMcpResource(error, uri.href);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
);
|
|
596
|
+
|
|
597
|
+
registerLogger.debug('Example resources registered successfully');
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
export default { registerResources };
|
|
601
|
+
```
|
|
602
|
+
|
|
487
603
|
</details>
|
|
488
604
|
|
|
489
605
|
## IP Address Example Implementation
|
|
@@ -494,26 +610,30 @@ The boilerplate includes a complete IP address geolocation example demonstrating
|
|
|
494
610
|
|
|
495
611
|
**CLI Commands:**
|
|
496
612
|
```bash
|
|
497
|
-
npm run cli -- get-ip-details # Get current public IP
|
|
498
|
-
npm run cli -- get-ip-details 8.8.8.8
|
|
613
|
+
npm run cli -- get-ip-details # Get current public IP (TOON format)
|
|
614
|
+
npm run cli -- get-ip-details 8.8.8.8 # Get details for specific IP
|
|
499
615
|
npm run cli -- get-ip-details 1.1.1.1 --include-extended-data # With extended data
|
|
500
|
-
npm run cli -- get-ip-details 8.8.8.8 --no-use-https
|
|
616
|
+
npm run cli -- get-ip-details 8.8.8.8 --no-use-https # Force HTTP (for free tier)
|
|
617
|
+
npm run cli -- get-ip-details 8.8.8.8 --output-format json # JSON output
|
|
618
|
+
npm run cli -- get-ip-details 8.8.8.8 --jq "{ip: query, country: country}" # Filtered output
|
|
501
619
|
```
|
|
502
620
|
|
|
503
621
|
**MCP Tools:**
|
|
504
622
|
- `ip_get_details` - IP geolocation lookup for AI assistants
|
|
623
|
+
- Supports `outputFormat`: "toon" (default) or "json"
|
|
624
|
+
- Supports `jq`: JMESPath expression for filtering
|
|
505
625
|
|
|
506
626
|
**MCP Resources:**
|
|
507
|
-
- `ip
|
|
508
|
-
- `ip://8.8.8.8` - Specific IP details
|
|
627
|
+
- `ip://{ipAddress}` - IP details resource template (e.g., `ip://8.8.8.8`)
|
|
509
628
|
|
|
510
629
|
### Features Demonstrated
|
|
511
630
|
|
|
631
|
+
- **TOON Output**: Token-efficient format (30-60% fewer tokens than JSON)
|
|
632
|
+
- **JMESPath Filtering**: Extract only needed fields to reduce costs
|
|
512
633
|
- **Fallback Logic**: HTTPS → HTTP fallback for free tier users
|
|
513
634
|
- **Environment Detection**: Different behavior in test vs production
|
|
514
635
|
- **API Token Support**: Optional token for extended data (ASN, mobile detection, etc.)
|
|
515
636
|
- **Error Handling**: Structured errors for private/reserved IP addresses
|
|
516
|
-
- **Response Formatting**: Clean Markdown output with geolocation data
|
|
517
637
|
|
|
518
638
|
### Configuration Options
|
|
519
639
|
|
|
@@ -592,9 +712,10 @@ npm run test:cli # CLI-specific tests only
|
|
|
592
712
|
## Resources & Documentation
|
|
593
713
|
|
|
594
714
|
### MCP Protocol Resources
|
|
595
|
-
- [MCP Specification](https://modelcontextprotocol.io/specification
|
|
596
|
-
- [MCP SDK Documentation](https://github.com/modelcontextprotocol/sdk)
|
|
715
|
+
- [MCP Specification](https://modelcontextprotocol.io/specification) - Latest protocol specification
|
|
716
|
+
- [MCP SDK Documentation](https://github.com/modelcontextprotocol/typescript-sdk) - TypeScript SDK v1.23.0+
|
|
597
717
|
- [MCP Inspector](https://github.com/modelcontextprotocol/inspector) - Visual debugging tool
|
|
718
|
+
- [MCP Concepts](https://modelcontextprotocol.io/docs/concepts) - Tools, resources, transports
|
|
598
719
|
|
|
599
720
|
### Implementation References
|
|
600
721
|
- [Anthropic MCP Announcement](https://www.anthropic.com/news/model-context-protocol)
|
package/STYLE_GUIDE.md
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
# MCP Server Style Guide
|
|
2
2
|
|
|
3
|
-
Based on the
|
|
3
|
+
Based on the MCP SDK v1.22.0+ best practices and observed patterns, this guide ensures consistency across all MCP servers.
|
|
4
|
+
|
|
5
|
+
## Naming Conventions
|
|
4
6
|
|
|
5
7
|
| Element | Convention | Rationale / Examples |
|
|
6
8
|
| :------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
7
9
|
| **CLI Commands** | `verb-noun` in `kebab-case`. Use the shortest unambiguous verb (`ls`, `get`, `create`, `add`, `exec`, `search`). | `ls-repos`, `get-pr`, `create-comment`, `exec-command` |
|
|
8
10
|
| **CLI Options** | `--kebab-case`. Be specific (e.g., `--workspace-slug`, not just `--slug`). | `--project-key-or-id`, `--source-branch` |
|
|
9
11
|
| **MCP Tool Names** | `<namespace>_<verb>_<noun>` in `snake_case`. Use a concise 2-4 char namespace. Avoid noun repetition. | `bb_ls_repos` (Bitbucket list repos), `conf_get_page` (Confluence get page), `aws_exec_command` (AWS execute command). Avoid `ip_ip_get_details`. |
|
|
12
|
+
| **MCP Resource Names**| `kebab-case`. Descriptive identifier for the resource type. | `ip-lookup`, `user-profile`, `config-data` |
|
|
10
13
|
| **MCP Arguments** | `camelCase`. Suffix identifiers consistently (e.g., `Id`, `Key`, `Slug`). Avoid abbreviations unless universal. | `workspaceSlug`, `pullRequestId`, `sourceBranch`, `pageId`. |
|
|
11
14
|
| **Boolean Args** | Use verb prefixes for clarity (`includeXxx`, `launchBrowser`). Avoid bare adjectives (`--https`). | `includeExtendedData: boolean`, `launchBrowser: boolean` |
|
|
12
15
|
| **Array Args** | Use plural names (`spaceIds`, `labels`, `statuses`). | `spaceIds: string[]`, `labels: string[]` |
|
|
@@ -14,4 +17,60 @@ Based on the patterns observed and best practices, I recommend adopting the foll
|
|
|
14
17
|
| **Arg Descriptions** | Start lowercase, explain purpose clearly. Mention defaults or constraints. | `numeric ID of the page to retrieve (e.g., "456789"). Required.` |
|
|
15
18
|
| **ID/Key Naming** | Use consistent suffixes like `Id`, `Key`, `Slug`, `KeyOrId` where appropriate. | `pageId`, `projectKeyOrId`, `workspaceSlug` |
|
|
16
19
|
|
|
20
|
+
## SDK Best Practices (v1.22.0+)
|
|
21
|
+
|
|
22
|
+
### Title vs Name
|
|
23
|
+
|
|
24
|
+
All registrations (`registerTool`, `registerResource`, `registerPrompt`) support both `name` and `title`:
|
|
25
|
+
|
|
26
|
+
| Field | Purpose | Example |
|
|
27
|
+
| :---- | :------ | :------ |
|
|
28
|
+
| `name` | Unique identifier for programmatic use | `ip_get_details` |
|
|
29
|
+
| `title` | Human-readable display name for UI | `IP Address Lookup` |
|
|
30
|
+
|
|
31
|
+
**Always provide both** - `name` for code, `title` for user interfaces.
|
|
32
|
+
|
|
33
|
+
### Modern Registration APIs
|
|
34
|
+
|
|
35
|
+
Use the modern `register*` methods instead of deprecated alternatives:
|
|
36
|
+
|
|
37
|
+
| Deprecated | Modern (SDK v1.22.0+) |
|
|
38
|
+
| :--------- | :-------------------- |
|
|
39
|
+
| `server.tool()` | `server.registerTool()` |
|
|
40
|
+
| `server.resource()` | `server.registerResource()` |
|
|
41
|
+
| `server.prompt()` | `server.registerPrompt()` |
|
|
42
|
+
|
|
43
|
+
### Resource Templates
|
|
44
|
+
|
|
45
|
+
Use `ResourceTemplate` for parameterized resource URIs:
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
49
|
+
|
|
50
|
+
// Static resource - fixed URI
|
|
51
|
+
server.registerResource('config', 'config://app', { ... }, handler);
|
|
52
|
+
|
|
53
|
+
// Dynamic resource - parameterized URI
|
|
54
|
+
server.registerResource(
|
|
55
|
+
'user-profile',
|
|
56
|
+
new ResourceTemplate('users://{userId}/profile', { list: undefined }),
|
|
57
|
+
{ title: 'User Profile', description: '...' },
|
|
58
|
+
async (uri, variables) => {
|
|
59
|
+
const userId = variables.userId as string;
|
|
60
|
+
// ...
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Error Handling
|
|
66
|
+
|
|
67
|
+
Use `isError: true` for tool execution failures:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
return {
|
|
71
|
+
content: [{ type: 'text', text: 'Error: Something went wrong' }],
|
|
72
|
+
isError: true
|
|
73
|
+
};
|
|
74
|
+
```
|
|
75
|
+
|
|
17
76
|
Adopting this guide will make the tools more predictable and easier for both humans and AI agents to understand and use correctly.
|
|
@@ -3,29 +3,34 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
6
7
|
const logger_util_js_1 = require("../utils/logger.util.js");
|
|
7
8
|
const ipaddress_controller_js_1 = __importDefault(require("../controllers/ipaddress.controller.js"));
|
|
8
9
|
const error_util_js_1 = require("../utils/error.util.js");
|
|
9
10
|
const logger = logger_util_js_1.Logger.forContext('resources/ipaddress.resource.ts');
|
|
10
11
|
/**
|
|
11
12
|
* Register an IP address lookup resource with the MCP server
|
|
13
|
+
* Uses the modern registerResource API (SDK v1.22.0+) with ResourceTemplate
|
|
12
14
|
*
|
|
13
15
|
* @param server The MCP server instance
|
|
14
16
|
*/
|
|
15
17
|
function registerResources(server) {
|
|
16
18
|
const registerLogger = logger.forMethod('registerResources');
|
|
17
19
|
registerLogger.debug('Registering IP lookup resources...');
|
|
18
|
-
// Register the IP lookup resource
|
|
19
|
-
|
|
20
|
+
// Register the IP lookup resource using modern registerResource API
|
|
21
|
+
// ResourceTemplate enables parameterized URIs with {ipAddress} placeholder
|
|
22
|
+
server.registerResource('ip-lookup', new mcp_js_1.ResourceTemplate('ip://{ipAddress}', { list: undefined }), {
|
|
23
|
+
title: 'IP Address Lookup', // Display name for UI
|
|
24
|
+
description: 'Retrieve geolocation and network information for a public IP address',
|
|
25
|
+
}, async (uri, variables) => {
|
|
20
26
|
const methodLogger = logger.forMethod('ipLookupResource');
|
|
21
27
|
try {
|
|
22
|
-
// Extract
|
|
23
|
-
|
|
28
|
+
// Extract ipAddress from template variables
|
|
29
|
+
const ipAddress = variables.ipAddress;
|
|
24
30
|
methodLogger.debug('IP lookup resource called', {
|
|
25
|
-
uri: uri.
|
|
31
|
+
uri: uri.href,
|
|
32
|
+
ipAddress,
|
|
26
33
|
});
|
|
27
|
-
// Get everything after the ip:// protocol
|
|
28
|
-
const ipAddress = uri.toString().replace(/^ip:\/\//, '');
|
|
29
34
|
// Call the controller to get the IP details
|
|
30
35
|
const result = await ipaddress_controller_js_1.default.get({
|
|
31
36
|
ipAddress: ipAddress || undefined,
|
|
@@ -36,17 +41,16 @@ function registerResources(server) {
|
|
|
36
41
|
return {
|
|
37
42
|
contents: [
|
|
38
43
|
{
|
|
39
|
-
uri: uri.
|
|
44
|
+
uri: uri.href,
|
|
40
45
|
text: result.content,
|
|
41
46
|
mimeType: 'text/markdown',
|
|
42
|
-
description: `IP Details for ${ipAddress || 'current'}`,
|
|
43
47
|
},
|
|
44
48
|
],
|
|
45
49
|
};
|
|
46
50
|
}
|
|
47
51
|
catch (error) {
|
|
48
52
|
methodLogger.error('Resource error', error);
|
|
49
|
-
return (0, error_util_js_1.formatErrorForMcpResource)(error, uri.
|
|
53
|
+
return (0, error_util_js_1.formatErrorForMcpResource)(error, uri.href);
|
|
50
54
|
}
|
|
51
55
|
});
|
|
52
56
|
registerLogger.debug('IP lookup resources registered successfully');
|
|
@@ -24,49 +24,7 @@ export declare const IPDetailSchema: z.ZodObject<{
|
|
|
24
24
|
mobile: z.ZodOptional<z.ZodBoolean>;
|
|
25
25
|
proxy: z.ZodOptional<z.ZodBoolean>;
|
|
26
26
|
hosting: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
-
},
|
|
28
|
-
status: string;
|
|
29
|
-
message?: string | undefined;
|
|
30
|
-
query?: string | undefined;
|
|
31
|
-
country?: string | undefined;
|
|
32
|
-
countryCode?: string | undefined;
|
|
33
|
-
region?: string | undefined;
|
|
34
|
-
regionName?: string | undefined;
|
|
35
|
-
city?: string | undefined;
|
|
36
|
-
zip?: string | undefined;
|
|
37
|
-
lat?: number | undefined;
|
|
38
|
-
lon?: number | undefined;
|
|
39
|
-
timezone?: string | undefined;
|
|
40
|
-
isp?: string | undefined;
|
|
41
|
-
org?: string | undefined;
|
|
42
|
-
as?: string | undefined;
|
|
43
|
-
asname?: string | undefined;
|
|
44
|
-
reverse?: string | undefined;
|
|
45
|
-
mobile?: boolean | undefined;
|
|
46
|
-
proxy?: boolean | undefined;
|
|
47
|
-
hosting?: boolean | undefined;
|
|
48
|
-
}, {
|
|
49
|
-
status: string;
|
|
50
|
-
message?: string | undefined;
|
|
51
|
-
query?: string | undefined;
|
|
52
|
-
country?: string | undefined;
|
|
53
|
-
countryCode?: string | undefined;
|
|
54
|
-
region?: string | undefined;
|
|
55
|
-
regionName?: string | undefined;
|
|
56
|
-
city?: string | undefined;
|
|
57
|
-
zip?: string | undefined;
|
|
58
|
-
lat?: number | undefined;
|
|
59
|
-
lon?: number | undefined;
|
|
60
|
-
timezone?: string | undefined;
|
|
61
|
-
isp?: string | undefined;
|
|
62
|
-
org?: string | undefined;
|
|
63
|
-
as?: string | undefined;
|
|
64
|
-
asname?: string | undefined;
|
|
65
|
-
reverse?: string | undefined;
|
|
66
|
-
mobile?: boolean | undefined;
|
|
67
|
-
proxy?: boolean | undefined;
|
|
68
|
-
hosting?: boolean | undefined;
|
|
69
|
-
}>;
|
|
27
|
+
}, z.core.$strip>;
|
|
70
28
|
/**
|
|
71
29
|
* TypeScript type inferred from the IPDetailSchema.
|
|
72
30
|
* Represents the expected structure of a successful ip-api.com response.
|
|
@@ -2,6 +2,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* @function registerTools
|
|
4
4
|
* @description Registers the IP address lookup tool ('ip_get_details') with the MCP server.
|
|
5
|
+
* Uses the modern registerTool API (SDK v1.22.0+) instead of deprecated tool() method.
|
|
5
6
|
*
|
|
6
7
|
* @param {McpServer} server - The MCP server instance.
|
|
7
8
|
*/
|
|
@@ -19,10 +19,6 @@ const GetIpDetailsToolSchema = zod_1.z.object({
|
|
|
19
19
|
.describe('IP address to lookup (omit for current IP)'),
|
|
20
20
|
...ipaddress_types_js_1.IpAddressToolArgs.shape, // Merge options schema
|
|
21
21
|
});
|
|
22
|
-
/**
|
|
23
|
-
* TypeScript type inferred from the combined tool arguments schema.
|
|
24
|
-
*/
|
|
25
|
-
// type GetIpDetailsToolArgsType = z.infer<typeof GetIpDetailsToolSchema>;
|
|
26
22
|
/**
|
|
27
23
|
* @function handleGetIpDetails
|
|
28
24
|
* @description MCP Tool handler to retrieve details for a given IP address (or the current IP).
|
|
@@ -55,15 +51,9 @@ async function handleGetIpDetails(args) {
|
|
|
55
51
|
}
|
|
56
52
|
}
|
|
57
53
|
/**
|
|
58
|
-
*
|
|
59
|
-
* @description Registers the IP address lookup tool ('ip_get_details') with the MCP server.
|
|
60
|
-
*
|
|
61
|
-
* @param {McpServer} server - The MCP server instance.
|
|
54
|
+
* Tool description for ip_get_details
|
|
62
55
|
*/
|
|
63
|
-
|
|
64
|
-
const methodLogger = logger_util_js_1.Logger.forContext('tools/ipaddress.tool.ts', 'registerTools');
|
|
65
|
-
methodLogger.debug(`Registering IP address tools...`);
|
|
66
|
-
server.tool('ip_get_details', `Retrieve geolocation and network information for a public IP address. Returns TOON format by default (30-60% fewer tokens than JSON).
|
|
56
|
+
const IP_GET_DETAILS_DESCRIPTION = `Retrieve geolocation and network information for a public IP address. Returns TOON format by default (30-60% fewer tokens than JSON).
|
|
67
57
|
|
|
68
58
|
**IMPORTANT - Cost Optimization:**
|
|
69
59
|
- Use \`jq\` param to extract only needed fields. Unfiltered responses are expensive!
|
|
@@ -85,7 +75,24 @@ function registerTools(server) {
|
|
|
85
75
|
|
|
86
76
|
**JQ examples:** \`query\` (IP only), \`{ip: query, country: country}\`, \`{location: {lat: lat, lon: lon}}\`
|
|
87
77
|
|
|
88
|
-
**Note:** Cannot lookup private IPs (192.168.x.x, 10.x.x.x). Powered by ip-api.com
|
|
78
|
+
**Note:** Cannot lookup private IPs (192.168.x.x, 10.x.x.x). Powered by ip-api.com.`;
|
|
79
|
+
/**
|
|
80
|
+
* @function registerTools
|
|
81
|
+
* @description Registers the IP address lookup tool ('ip_get_details') with the MCP server.
|
|
82
|
+
* Uses the modern registerTool API (SDK v1.22.0+) instead of deprecated tool() method.
|
|
83
|
+
*
|
|
84
|
+
* @param {McpServer} server - The MCP server instance.
|
|
85
|
+
*/
|
|
86
|
+
function registerTools(server) {
|
|
87
|
+
const methodLogger = logger_util_js_1.Logger.forContext('tools/ipaddress.tool.ts', 'registerTools');
|
|
88
|
+
methodLogger.debug(`Registering IP address tools...`);
|
|
89
|
+
// Use the modern registerTool API (SDK v1.22.0+)
|
|
90
|
+
// Following SDK best practices: title for UI display, description for details
|
|
91
|
+
server.registerTool('ip_get_details', {
|
|
92
|
+
title: 'IP Address Lookup',
|
|
93
|
+
description: IP_GET_DETAILS_DESCRIPTION,
|
|
94
|
+
inputSchema: GetIpDetailsToolSchema,
|
|
95
|
+
}, handleGetIpDetails);
|
|
89
96
|
methodLogger.debug('Successfully registered ip_get_details tool.');
|
|
90
97
|
}
|
|
91
98
|
exports.default = { registerTools };
|
|
@@ -4,7 +4,10 @@ import { z } from 'zod';
|
|
|
4
4
|
* - toon: Token-Oriented Object Notation (default, more token-efficient for LLMs)
|
|
5
5
|
* - json: Standard JSON format
|
|
6
6
|
*/
|
|
7
|
-
export declare const OutputFormat: z.ZodOptional<z.ZodEnum<
|
|
7
|
+
export declare const OutputFormat: z.ZodOptional<z.ZodEnum<{
|
|
8
|
+
toon: "toon";
|
|
9
|
+
json: "json";
|
|
10
|
+
}>>;
|
|
8
11
|
/**
|
|
9
12
|
* Zod schema for the IP address tool arguments.
|
|
10
13
|
*/
|
|
@@ -12,18 +15,11 @@ export declare const IpAddressToolArgs: z.ZodObject<{
|
|
|
12
15
|
includeExtendedData: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
13
16
|
useHttps: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
14
17
|
jq: z.ZodOptional<z.ZodString>;
|
|
15
|
-
outputFormat: z.ZodOptional<z.ZodEnum<
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
outputFormat?: "toon" | "json" | undefined;
|
|
21
|
-
}, {
|
|
22
|
-
useHttps?: boolean | undefined;
|
|
23
|
-
includeExtendedData?: boolean | undefined;
|
|
24
|
-
jq?: string | undefined;
|
|
25
|
-
outputFormat?: "toon" | "json" | undefined;
|
|
26
|
-
}>;
|
|
18
|
+
outputFormat: z.ZodOptional<z.ZodEnum<{
|
|
19
|
+
toon: "toon";
|
|
20
|
+
json: "json";
|
|
21
|
+
}>>;
|
|
22
|
+
}, z.core.$strict>;
|
|
27
23
|
/**
|
|
28
24
|
* TypeScript type inferred from the IpAddressToolArgs Zod schema.
|
|
29
25
|
* This represents the optional arguments passed to the tool handler and controller.
|
|
@@ -11,7 +11,7 @@ exports.CLI_NAME = exports.PACKAGE_NAME = exports.VERSION = void 0;
|
|
|
11
11
|
* Current application version
|
|
12
12
|
* This should match the version in package.json
|
|
13
13
|
*/
|
|
14
|
-
exports.VERSION = '1.
|
|
14
|
+
exports.VERSION = '1.16.0';
|
|
15
15
|
/**
|
|
16
16
|
* Package name with scope
|
|
17
17
|
* Used for initialization and identification
|
|
@@ -134,7 +134,6 @@ async function fetchApi(url, options = {}) {
|
|
|
134
134
|
try {
|
|
135
135
|
const responseData = await response.json();
|
|
136
136
|
methodLogger.debug('Response body successfully parsed as JSON.');
|
|
137
|
-
// methodLogger.debug('Response Data:', responseData); // Uncomment for full response logging
|
|
138
137
|
return responseData;
|
|
139
138
|
}
|
|
140
139
|
catch (parseError) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aashari/boilerplate-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.16.0",
|
|
4
4
|
"description": "TypeScript MCP server boilerplate with STDIO and HTTP transport support, CLI tools, and extensible architecture",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -51,38 +51,38 @@
|
|
|
51
51
|
"node": ">=18.0.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@eslint/js": "^9.
|
|
54
|
+
"@eslint/js": "^9.39.1",
|
|
55
55
|
"@semantic-release/changelog": "^6.0.3",
|
|
56
56
|
"@semantic-release/exec": "^7.1.0",
|
|
57
57
|
"@semantic-release/git": "^10.0.1",
|
|
58
|
-
"@semantic-release/github": "^
|
|
59
|
-
"@semantic-release/npm": "^
|
|
58
|
+
"@semantic-release/github": "^12.0.2",
|
|
59
|
+
"@semantic-release/npm": "^13.1.2",
|
|
60
60
|
"@types/cors": "^2.8.19",
|
|
61
|
-
"@types/express": "^5.0.
|
|
61
|
+
"@types/express": "^5.0.5",
|
|
62
62
|
"@types/jest": "^30.0.0",
|
|
63
63
|
"@types/jmespath": "^0.15.2",
|
|
64
|
-
"@types/node": "^24.
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
66
|
-
"@typescript-eslint/parser": "^8.
|
|
67
|
-
"eslint": "^9.
|
|
64
|
+
"@types/node": "^24.10.1",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^8.48.0",
|
|
66
|
+
"@typescript-eslint/parser": "^8.48.0",
|
|
67
|
+
"eslint": "^9.39.1",
|
|
68
68
|
"eslint-config-prettier": "^10.1.8",
|
|
69
69
|
"eslint-plugin-prettier": "^5.5.4",
|
|
70
|
-
"jest": "^30.
|
|
71
|
-
"prettier": "^3.
|
|
72
|
-
"semantic-release": "^
|
|
73
|
-
"ts-jest": "^29.4.
|
|
74
|
-
"typescript": "^5.9.
|
|
75
|
-
"typescript-eslint": "^8.
|
|
70
|
+
"jest": "^30.2.0",
|
|
71
|
+
"prettier": "^3.7.3",
|
|
72
|
+
"semantic-release": "^25.0.2",
|
|
73
|
+
"ts-jest": "^29.4.5",
|
|
74
|
+
"typescript": "^5.9.3",
|
|
75
|
+
"typescript-eslint": "^8.48.0"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
78
|
+
"@modelcontextprotocol/sdk": "^1.23.0",
|
|
79
79
|
"@toon-format/toon": "^2.0.1",
|
|
80
|
-
"commander": "^14.0.
|
|
80
|
+
"commander": "^14.0.2",
|
|
81
81
|
"cors": "^2.8.5",
|
|
82
|
-
"dotenv": "^17.2.
|
|
82
|
+
"dotenv": "^17.2.3",
|
|
83
83
|
"express": "^5.1.0",
|
|
84
84
|
"jmespath": "^0.16.0",
|
|
85
|
-
"zod": "^
|
|
85
|
+
"zod": "^4.1.13"
|
|
86
86
|
},
|
|
87
87
|
"publishConfig": {
|
|
88
88
|
"registry": "https://registry.npmjs.org/",
|
package/package.json.bak
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aashari/boilerplate-mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "TypeScript MCP server boilerplate with STDIO and HTTP transport support, CLI tools, and extensible architecture",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -51,38 +51,38 @@
|
|
|
51
51
|
"node": ">=18.0.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@eslint/js": "^9.
|
|
54
|
+
"@eslint/js": "^9.39.1",
|
|
55
55
|
"@semantic-release/changelog": "^6.0.3",
|
|
56
56
|
"@semantic-release/exec": "^7.1.0",
|
|
57
57
|
"@semantic-release/git": "^10.0.1",
|
|
58
|
-
"@semantic-release/github": "^
|
|
59
|
-
"@semantic-release/npm": "^
|
|
58
|
+
"@semantic-release/github": "^12.0.2",
|
|
59
|
+
"@semantic-release/npm": "^13.1.2",
|
|
60
60
|
"@types/cors": "^2.8.19",
|
|
61
|
-
"@types/express": "^5.0.
|
|
61
|
+
"@types/express": "^5.0.5",
|
|
62
62
|
"@types/jest": "^30.0.0",
|
|
63
63
|
"@types/jmespath": "^0.15.2",
|
|
64
|
-
"@types/node": "^24.
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
66
|
-
"@typescript-eslint/parser": "^8.
|
|
67
|
-
"eslint": "^9.
|
|
64
|
+
"@types/node": "^24.10.1",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^8.48.0",
|
|
66
|
+
"@typescript-eslint/parser": "^8.48.0",
|
|
67
|
+
"eslint": "^9.39.1",
|
|
68
68
|
"eslint-config-prettier": "^10.1.8",
|
|
69
69
|
"eslint-plugin-prettier": "^5.5.4",
|
|
70
|
-
"jest": "^30.
|
|
71
|
-
"prettier": "^3.
|
|
72
|
-
"semantic-release": "^
|
|
73
|
-
"ts-jest": "^29.4.
|
|
74
|
-
"typescript": "^5.9.
|
|
75
|
-
"typescript-eslint": "^8.
|
|
70
|
+
"jest": "^30.2.0",
|
|
71
|
+
"prettier": "^3.7.3",
|
|
72
|
+
"semantic-release": "^25.0.2",
|
|
73
|
+
"ts-jest": "^29.4.5",
|
|
74
|
+
"typescript": "^5.9.3",
|
|
75
|
+
"typescript-eslint": "^8.48.0"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
78
|
+
"@modelcontextprotocol/sdk": "^1.23.0",
|
|
79
79
|
"@toon-format/toon": "^2.0.1",
|
|
80
|
-
"commander": "^14.0.
|
|
80
|
+
"commander": "^14.0.2",
|
|
81
81
|
"cors": "^2.8.5",
|
|
82
|
-
"dotenv": "^17.2.
|
|
82
|
+
"dotenv": "^17.2.3",
|
|
83
83
|
"express": "^5.1.0",
|
|
84
84
|
"jmespath": "^0.16.0",
|
|
85
|
-
"zod": "^
|
|
85
|
+
"zod": "^4.1.13"
|
|
86
86
|
},
|
|
87
87
|
"publishConfig": {
|
|
88
88
|
"registry": "https://registry.npmjs.org/",
|