Skip to content

Commit 303a8d9

Browse files
danh91claude
andcommitted
fix(mcp): remove validate_address, add list_carrier_connections, clean up tests
Remove validate_address references (unsupported feature) from README, tests, and client. Add list_carrier_connections tool to carriers module. Remove console.log statements from integration tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6a78979 commit 303a8d9

5 files changed

Lines changed: 86 additions & 39 deletions

File tree

packages/mcp/README.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Connect any AI agent (Claude, ChatGPT, Cursor, VS Code Copilot) to 50+ shipping
66

77
## Features
88

9-
- **11 shipping tools** -- rates, labels, tracking, address validation, pickups, manifests, orders, and more
9+
- **10 shipping tools** -- rates, labels, tracking, pickups, manifests, orders, and more
1010
- **MCP Resources** for a live carrier capability catalog -- no other shipping MCP does this
1111
- **stdio + Streamable HTTP** transport (remote-ready)
1212
- **Works with any Karrio instance** -- cloud or self-hosted
@@ -114,7 +114,6 @@ The server exposes:
114114
| `list_shipments` | List shipments with status, carrier, and date filters | No |
115115
| `cancel_shipment` | Cancel a shipment and void its label | Yes |
116116
| `track_package` | Track a package by tracking number with full event history | No |
117-
| `validate_address` | Validate and correct a shipping address | No |
118117
| `list_carriers` | List connected carriers and their capabilities | No |
119118
| `schedule_pickup` | Schedule a carrier pickup for one or more shipments | Yes |
120119
| `create_manifest` | Create an end-of-day manifest (SCAN form) | Yes |
@@ -128,8 +127,6 @@ The server exposes:
128127

129128
**`track_package`** -- Real-time package tracking. Provide a tracking number and optionally a carrier name (auto-detection is supported). Returns status, estimated delivery, and a chronological event history with locations.
130129

131-
**`validate_address`** -- Verify addresses before shipping. Returns the validated/corrected address with any corrections applied by the carrier.
132-
133130
**`list_carriers`** -- Discover which carriers are connected to your Karrio instance and what capabilities each supports (tracking, rating, shipping, pickup).
134131

135132
**`schedule_pickup`** -- Book a carrier pickup at a specified address with date, ready time, and closing time windows. Optionally include specific shipment IDs.
@@ -197,8 +194,7 @@ src/
197194
rates.ts get_shipping_rates
198195
shipments.ts create_shipment, get_shipment, list_shipments, cancel_shipment
199196
tracking.ts track_package
200-
addresses.ts validate_address
201-
carriers.ts list_carriers
197+
carriers.ts list_carriers, list_carrier_connections
202198
pickups.ts schedule_pickup
203199
manifests.ts create_manifest
204200
orders.ts list_orders

packages/mcp/src/client.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,16 @@ export class KarrioClient {
9696
return this.request("GET", "/v1/trackers", { params });
9797
}
9898

99-
// Address validation
100-
async validateAddress(payload: Record<string, unknown>): Promise<any> {
101-
return this.request("POST", "/v1/addresses/validate", { body: payload });
102-
}
103-
10499
// Carriers
105100
async listCarriers(params?: Record<string, string>): Promise<any> {
106101
return this.request("GET", "/v1/carriers", { params });
107102
}
108103

104+
// Carrier connections (configured accounts)
105+
async listConnections(params?: Record<string, string>): Promise<any> {
106+
return this.request("GET", "/v1/connections", { params });
107+
}
108+
109109
// Reference data
110110
async getReferences(): Promise<any> {
111111
return this.request("GET", "/v1/references");

packages/mcp/src/tools/carriers.ts

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export function registerCarrierTools(
88
): void {
99
server.tool(
1010
"list_carriers",
11-
"List all carrier accounts connected to your Karrio instance with their capabilities (tracking, rating, shipping, pickup). Use this to discover available carriers and their service codes before creating shipments or fetching rates.",
11+
"List all supported carrier integrations in the Karrio catalog with their capabilities. Use this to discover what carriers can be connected. For carriers already connected to your account, use list_carrier_connections instead.",
1212
{
1313
carrier_name: z
1414
.string()
@@ -47,10 +47,8 @@ export function registerCarrierTools(
4747
(carrier: any) => ({
4848
id: carrier.id,
4949
carrier_name: carrier.carrier_name,
50-
carrier_id: carrier.carrier_id,
51-
active: carrier.active ?? carrier.is_active ?? null,
50+
display_name: carrier.display_name ?? null,
5251
capabilities: carrier.capabilities ?? [],
53-
test_mode: carrier.test_mode ?? null,
5452
}),
5553
);
5654

@@ -79,4 +77,79 @@ export function registerCarrierTools(
7977
}
8078
},
8179
);
80+
81+
server.tool(
82+
"list_carrier_connections",
83+
"List carrier accounts connected to your Karrio instance. These are the carriers configured with credentials that you can use for rating, shipping, and tracking. Returns carrier_id, display_name, capabilities, and connection status.",
84+
{
85+
carrier_name: z
86+
.string()
87+
.optional()
88+
.describe("Filter by carrier name (e.g., 'fedex', 'ups')"),
89+
limit: z
90+
.number()
91+
.int()
92+
.default(20)
93+
.describe("Maximum results"),
94+
offset: z
95+
.number()
96+
.int()
97+
.default(0)
98+
.describe("Pagination offset"),
99+
},
100+
{
101+
readOnlyHint: true,
102+
destructiveHint: false,
103+
idempotentHint: true,
104+
openWorldHint: false,
105+
},
106+
async (params) => {
107+
try {
108+
const queryParams: Record<string, string> = {
109+
limit: String(params.limit),
110+
offset: String(params.offset),
111+
};
112+
if (params.carrier_name) {
113+
queryParams.carrier_name = params.carrier_name;
114+
}
115+
116+
const response = await client.listConnections(queryParams);
117+
118+
const connections = (response.results ?? []).map(
119+
(conn: any) => ({
120+
id: conn.id,
121+
carrier_name: conn.carrier_name,
122+
carrier_id: conn.carrier_id,
123+
display_name: conn.display_name ?? null,
124+
capabilities: conn.capabilities ?? [],
125+
active: conn.active ?? conn.is_active ?? null,
126+
test_mode: conn.test_mode ?? null,
127+
}),
128+
);
129+
130+
const result = {
131+
connections,
132+
count: response.count ?? connections.length,
133+
limit: params.limit,
134+
offset: params.offset,
135+
};
136+
137+
return {
138+
content: [
139+
{ type: "text", text: JSON.stringify(result, null, 2) },
140+
],
141+
};
142+
} catch (error: any) {
143+
return {
144+
content: [
145+
{
146+
type: "text",
147+
text: `Error listing carrier connections: ${error.message}`,
148+
},
149+
],
150+
isError: true,
151+
};
152+
}
153+
},
154+
);
82155
}

packages/mcp/tests/integration/server.test.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ describe("MCP Server", () => {
88
apiKey: "test_key",
99
});
1010

11-
// Server should be created without errors
12-
console.log(server);
1311
expect(server).toBeDefined();
1412
});
1513

@@ -19,7 +17,7 @@ describe("MCP Server", () => {
1917
apiKey: "custom_key",
2018
});
2119

22-
console.log(server);
20+
2321
expect(server).toBeDefined();
2422
});
2523

@@ -33,7 +31,7 @@ describe("MCP Server", () => {
3331
apiKey: "test_key",
3432
});
3533

36-
console.log(server);
34+
3735
expect(server).toBeInstanceOf(McpServer);
3836
});
3937

@@ -48,8 +46,6 @@ describe("MCP Server", () => {
4846
apiKey: "key_2",
4947
});
5048

51-
console.log(server1);
52-
console.log(server2);
5349
expect(server1).not.toBe(server2);
5450
});
5551
});

packages/mcp/tests/unit/client.test.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -263,24 +263,6 @@ describe("KarrioClient", () => {
263263
);
264264
});
265265

266-
it("calls correct URL for validateAddress", async () => {
267-
global.fetch = vi.fn().mockResolvedValue({
268-
ok: true,
269-
json: () => Promise.resolve({ valid: true }),
270-
});
271-
272-
const payload = { address: { postal_code: "10001", country_code: "US" } };
273-
const result = await client.validateAddress(payload);
274-
275-
276-
expect(fetch).toHaveBeenCalledWith(
277-
"https://api.karrio.io/v1/addresses/validate",
278-
expect.objectContaining({
279-
method: "POST",
280-
body: JSON.stringify(payload),
281-
}),
282-
);
283-
});
284266

285267
it("calls correct URL for getReferences", async () => {
286268
global.fetch = vi.fn().mockResolvedValue({

0 commit comments

Comments
 (0)