@sthan/mcp-server 0.1.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/README.md ADDED
@@ -0,0 +1,96 @@
1
+ # @sthan/mcp-server
2
+
3
+ MCP server for [sthan.io](https://sthan.io) — US address verification, parsing, autocomplete, geocoding, and IP geolocation.
4
+
5
+ Works with Claude Code, Cursor, VS Code, Windsurf, and any MCP-compatible client.
6
+
7
+ ## Setup
8
+
9
+ ### 1. Get an API key
10
+
11
+ Sign up at [sthan.io](https://sthan.io) (free tier, no credit card required). Create an API key from your [dashboard](https://sthan.io/dashboard).
12
+
13
+ ### 2. Configure your client
14
+
15
+ **Claude Code** (`~/.claude/mcp.json` or project `.claude/mcp.json`):
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "sthan": {
21
+ "command": "npx",
22
+ "args": ["@sthan/mcp-server"],
23
+ "env": { "STHAN_API_KEY": "sthan_test_your_api_key_here" }
24
+ }
25
+ }
26
+ }
27
+ ```
28
+
29
+ **Cursor** (`.cursor/mcp.json`):
30
+
31
+ ```json
32
+ {
33
+ "mcpServers": {
34
+ "sthan": {
35
+ "command": "npx",
36
+ "args": ["@sthan/mcp-server"],
37
+ "env": { "STHAN_API_KEY": "sthan_test_your_api_key_here" }
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ **VS Code** (`settings.json`):
44
+
45
+ ```json
46
+ {
47
+ "mcp.servers": {
48
+ "sthan": {
49
+ "command": "npx",
50
+ "args": ["@sthan/mcp-server"],
51
+ "env": { "STHAN_API_KEY": "sthan_test_your_api_key_here" }
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ ## Tools
58
+
59
+ | Tool | Description |
60
+ |------|-------------|
61
+ | `sthan_verify_address` | Verify a US address for deliverability. Returns DPV confirmation, ZIP+4, carrier route. |
62
+ | `sthan_parse_address` | Parse freeform address text into structured components (street, city, state, zip, unit). |
63
+ | `sthan_autocomplete_address` | Get address suggestions from partial input. Sub-100ms response time. |
64
+ | `sthan_autocomplete_city` | Get US city suggestions from partial input. |
65
+ | `sthan_autocomplete_zipcode` | Get US ZIP code suggestions from partial input. |
66
+ | `sthan_geocode` | Convert a US address to latitude/longitude coordinates. |
67
+ | `sthan_reverse_geocode` | Convert coordinates to the nearest US street address. |
68
+ | `sthan_ip_geolocation` | Look up geographic location of an IPv4 or IPv6 address. |
69
+
70
+ ## Environment variables
71
+
72
+ | Variable | Required | Description |
73
+ |----------|----------|-------------|
74
+ | `STHAN_API_KEY` | Yes | Your sthan.io API key (`sthan_test_*` or `sthan_live_*`) |
75
+ | `STHAN_API_URL` | No | Override base URL (default: `https://api.sthan.io`) |
76
+
77
+ ## Examples
78
+
79
+ Once configured, just ask your AI assistant naturally:
80
+
81
+ - "Is 123 Main St, New York, NY 10001 a real address?"
82
+ - "Parse this address: apt 2b 500 broadway new york ny"
83
+ - "What are the coordinates for the White House?"
84
+ - "What address is at 40.7128, -74.0060?"
85
+ - "Where is IP 8.8.8.8 located?"
86
+
87
+ ## Links
88
+
89
+ - [API docs](https://sthan.io/docs)
90
+ - [Pricing](https://sthan.io/pricing/united-states)
91
+ - [OpenAPI spec](https://api.sthan.io/openapi.json)
92
+ - [AI reference](https://api.sthan.io/llms-full.txt)
93
+
94
+ ## License
95
+
96
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const core_1 = require("@sthan/core");
7
+ const zod_1 = require("zod");
8
+ const apiKey = process.env.STHAN_API_KEY;
9
+ if (!apiKey) {
10
+ console.error("Error: STHAN_API_KEY environment variable is required.\n" +
11
+ "Get your API key at https://sthan.io/dashboard\n" +
12
+ "Set it: export STHAN_API_KEY=sthan_test_your_key_here");
13
+ process.exit(1);
14
+ }
15
+ const client = new core_1.SthanClient({
16
+ apiKey,
17
+ baseUrl: process.env.STHAN_API_URL,
18
+ });
19
+ const server = new mcp_js_1.McpServer({
20
+ name: "sthan",
21
+ version: "0.1.0",
22
+ });
23
+ // --- Tool 1: Verify US Address ---
24
+ server.tool("sthan_verify_address", "Verify if a US address is real and deliverable. Returns standardized format, ZIP+4, delivery point validation (DPV), and whether it's residential or commercial. Use when someone asks 'is this address real?', 'can mail be delivered here?', or 'verify this address'.", {
25
+ address: zod_1.z
26
+ .string()
27
+ .describe("Full or partial US address in any format. Examples: '123 Main St, New York, NY 10001', '123 main st nyc', '1600 Pennsylvania Ave Washington DC'"),
28
+ }, async ({ address }) => {
29
+ try {
30
+ const response = await client.verifyAddress(address);
31
+ return {
32
+ content: [{ type: "text", text: JSON.stringify(response.Result, null, 2) }],
33
+ };
34
+ }
35
+ catch (e) {
36
+ return errorResult(e);
37
+ }
38
+ });
39
+ // --- Tool 2: Parse US Address ---
40
+ server.tool("sthan_parse_address", "Parse a freeform US address string into structured components (street number, name, type, direction, unit, city, state, zip). Use when someone has messy or unstructured address text and needs it broken into parts.", {
41
+ address: zod_1.z
42
+ .string()
43
+ .describe("Raw address text to parse. Freeform input, abbreviations OK. Example: 'apt 2b 500 broadway new york ny'"),
44
+ }, async ({ address }) => {
45
+ try {
46
+ const response = await client.parseAddress(address);
47
+ return {
48
+ content: [{ type: "text", text: JSON.stringify(response.Result, null, 2) }],
49
+ };
50
+ }
51
+ catch (e) {
52
+ return errorResult(e);
53
+ }
54
+ });
55
+ // --- Tool 3: Autocomplete US Address ---
56
+ server.tool("sthan_autocomplete_address", "Get address suggestions from partial input. Sub-100ms response time. Returns array of complete US address strings. Use for type-ahead address completion.", {
57
+ text: zod_1.z
58
+ .string()
59
+ .describe("Partial address text (3+ characters recommended). Example: '123 Main'"),
60
+ }, async ({ text }) => {
61
+ try {
62
+ const response = await client.autocompleteAddress(text);
63
+ return {
64
+ content: [{ type: "text", text: JSON.stringify(response.Result, null, 2) }],
65
+ };
66
+ }
67
+ catch (e) {
68
+ return errorResult(e);
69
+ }
70
+ });
71
+ // --- Tool 4: Autocomplete US City ---
72
+ server.tool("sthan_autocomplete_city", "Get US city name suggestions from partial input. Returns matching cities with state.", {
73
+ text: zod_1.z.string().describe("Partial city name. Example: 'San Fr'"),
74
+ display_type: zod_1.z
75
+ .number()
76
+ .int()
77
+ .min(0)
78
+ .max(1)
79
+ .default(0)
80
+ .describe("0 = City, StateCode (e.g. 'San Francisco, CA'). 1 = City, State (e.g. 'San Francisco, California')"),
81
+ }, async ({ text, display_type }) => {
82
+ try {
83
+ const response = await client.autocompleteCity(text, display_type);
84
+ return {
85
+ content: [{ type: "text", text: JSON.stringify(response.Result, null, 2) }],
86
+ };
87
+ }
88
+ catch (e) {
89
+ return errorResult(e);
90
+ }
91
+ });
92
+ // --- Tool 5: Autocomplete US ZIP Code ---
93
+ server.tool("sthan_autocomplete_zipcode", "Get US ZIP code suggestions from partial input.", {
94
+ text: zod_1.z.string().describe("Partial ZIP code. Example: '9021'"),
95
+ display_type: zod_1.z
96
+ .number()
97
+ .int()
98
+ .min(0)
99
+ .max(3)
100
+ .default(0)
101
+ .describe("0 = Zip,StateCode. 1 = Zip,State. 2 = Zip-Zip4,StateCode. 3 = Zip-Zip4,State"),
102
+ }, async ({ text, display_type }) => {
103
+ try {
104
+ const response = await client.autocompleteZipCode(text, display_type);
105
+ return {
106
+ content: [{ type: "text", text: JSON.stringify(response.Result, null, 2) }],
107
+ };
108
+ }
109
+ catch (e) {
110
+ return errorResult(e);
111
+ }
112
+ });
113
+ // --- Tool 6: Forward Geocode US Address ---
114
+ server.tool("sthan_geocode", "Convert a US address to latitude/longitude coordinates. Returns accuracy type (rooftop, interpolated, centroid, approximate) and confidence score. Use when someone needs coordinates for an address.", {
115
+ address: zod_1.z
116
+ .string()
117
+ .describe("US address to geocode (freeform text). Example: '1600 Pennsylvania Ave, Washington DC'"),
118
+ }, async ({ address }) => {
119
+ try {
120
+ const response = await client.geocodeAddress(address);
121
+ return {
122
+ content: [{ type: "text", text: JSON.stringify(response.Result, null, 2) }],
123
+ };
124
+ }
125
+ catch (e) {
126
+ return errorResult(e);
127
+ }
128
+ });
129
+ // --- Tool 7: Reverse Geocode ---
130
+ server.tool("sthan_reverse_geocode", "Convert latitude/longitude coordinates to the nearest US street address. Returns the address with distance in meters from input coordinates. Use when someone has coordinates and wants the address.", {
131
+ latitude: zod_1.z.number().min(-90).max(90).describe("Latitude coordinate"),
132
+ longitude: zod_1.z.number().min(-180).max(180).describe("Longitude coordinate"),
133
+ }, async ({ latitude, longitude }) => {
134
+ try {
135
+ const response = await client.reverseGeocode(latitude, longitude);
136
+ return {
137
+ content: [{ type: "text", text: JSON.stringify(response.Result, null, 2) }],
138
+ };
139
+ }
140
+ catch (e) {
141
+ return errorResult(e);
142
+ }
143
+ });
144
+ // --- Tool 8: IP Geolocation ---
145
+ server.tool("sthan_ip_geolocation", "Look up the geographic location of an IPv4 or IPv6 address. Returns country, region, city, coordinates, timezone, and postal code. Use when someone wants to know where an IP address is located.", {
146
+ ip: zod_1.z
147
+ .string()
148
+ .describe("IPv4 (e.g. '8.8.8.8') or IPv6 (e.g. '2001:4860:4860::8888') address"),
149
+ }, async ({ ip }) => {
150
+ try {
151
+ const response = await client.ipGeolocation(ip);
152
+ return {
153
+ content: [{ type: "text", text: JSON.stringify(response.Result, null, 2) }],
154
+ };
155
+ }
156
+ catch (e) {
157
+ return errorResult(e);
158
+ }
159
+ });
160
+ // --- Error helper ---
161
+ function errorResult(e) {
162
+ if (e instanceof core_1.SthanApiError) {
163
+ return {
164
+ content: [
165
+ {
166
+ type: "text",
167
+ text: `Error (${e.statusCode}): ${e.message}`,
168
+ },
169
+ ],
170
+ isError: true,
171
+ };
172
+ }
173
+ const msg = e instanceof Error ? e.message : String(e);
174
+ return {
175
+ content: [{ type: "text", text: `Error: ${msg}` }],
176
+ isError: true,
177
+ };
178
+ }
179
+ // --- Start server ---
180
+ async function main() {
181
+ const transport = new stdio_js_1.StdioServerTransport();
182
+ await server.connect(transport);
183
+ }
184
+ main().catch((e) => {
185
+ console.error("Fatal:", e);
186
+ process.exit(1);
187
+ });
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@sthan/mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for sthan.io — US address verification, parsing, autocomplete, geocoding, and IP geolocation",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "sthan-mcp-server": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "start": "node dist/index.js"
18
+ },
19
+ "keywords": [
20
+ "mcp",
21
+ "mcp-server",
22
+ "model-context-protocol",
23
+ "address-verification",
24
+ "address-parser",
25
+ "address-autocomplete",
26
+ "geocoding",
27
+ "reverse-geocoding",
28
+ "ip-geolocation",
29
+ "sthan",
30
+ "claude",
31
+ "cursor",
32
+ "vscode",
33
+ "ai",
34
+ "ai-tools"
35
+ ],
36
+ "author": "sthan.io",
37
+ "license": "MIT",
38
+ "homepage": "https://sthan.io",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/nishka-llc/sthan"
42
+ },
43
+ "engines": {
44
+ "node": ">=20"
45
+ },
46
+ "dependencies": {
47
+ "@modelcontextprotocol/sdk": "^1.12.1",
48
+ "@sthan/core": "0.1.0"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^25.5.0",
52
+ "typescript": "^6.0.2"
53
+ }
54
+ }