Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ console.log(servers);
// Example: ['time', 'fetch', 'git']

// List tool definitions for a specific server
const tools = await client.servers.time.listTools();
const tools = await client.servers.time.getTools();
console.log(tools);

// Dynamically call a tool via the .tools namespace
Expand Down Expand Up @@ -79,7 +79,7 @@ const client = new McpdClient({
const servers: string[] = await client.listServers();

// Get tools with proper typing
const tools: Tool[] = await client.servers.time.listTools();
const tools: Tool[] = await client.servers.time.getTools();

// Dynamic tool invocation with error handling via .tools namespace
try {
Expand Down Expand Up @@ -122,7 +122,7 @@ const servers = await client.listServers();
// Returns: ['time', 'fetch', 'git']
```

#### `client.getToolSchemas(options?)`
#### `client.getTools(options?)`

Returns tool schemas from all (or specific) servers with names transformed to `serverName__toolName` format.

Expand All @@ -136,24 +136,24 @@ This is useful for:

```typescript
// Get all tools from all servers
const allTools = await client.getToolSchemas();
const allTools = await client.getTools();
// Returns: [
// { name: "time__get_current_time", description: "...", inputSchema: {...} },
// { name: "fetch__fetch_url", description: "...", inputSchema: {...} },
// { name: "git__commit", description: "...", inputSchema: {...} }
// ]

// Get tools from specific servers only
const someTools = await client.getToolSchemas({ servers: ["time", "fetch"] });
const someTools = await client.getTools({ servers: ["time", "fetch"] });
```

#### `client.servers.<server>.listTools()`
#### `client.servers.<server>.getTools()`

Returns tool schemas for a specific server.

```typescript
// Get tools for a specific server
const timeTools = await client.servers.time.listTools();
const timeTools = await client.servers.time.getTools();
// Returns: [{ name: 'get_current_time', description: '...', inputSchema: {...} }]
```

Expand All @@ -172,21 +172,21 @@ const result = await client.servers.weather.tools.get_forecast({
const time = await client.servers.time.tools.get_current_time();
```

#### `client.servers.<server>.listTools()`
#### `client.servers.<server>.getTools()`

List all tools available on a specific server.
Get all tools available on a specific server.

```typescript
// List tools for a server using property access
const tools = await client.servers.time.listTools();
const tools = await client.servers.time.getTools();
for (const tool of tools) {
console.log(`${tool.name}: ${tool.description}`);
}

// Useful in loops with dynamic server names
const servers = await client.listServers();
for (const serverName of servers) {
const tools = await client.servers[serverName].listTools();
const tools = await client.servers[serverName].getTools();
console.log(`${serverName}: ${tools.length} tools`);
}
```
Expand Down
2 changes: 1 addition & 1 deletion examples/basic/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ async function main() {
if (servers.includes('time')) {
// Get tools for the time server
console.log('Time server tools:');
const tools = await client.servers.time.listTools();
const tools = await client.servers.time.getTools();
for (const tool of tools) {
console.log(` - ${tool.name}: ${tool.description || 'No description'}`);
}
Expand Down
32 changes: 11 additions & 21 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,20 +295,20 @@ export class McpdClient {
* @example
* ```typescript
* // Get all tools from all servers
* const allTools = await client.getToolSchemas();
* const allTools = await client.getTools();
* // Returns: [
* // { name: "time__get_current_time", description: "...", ... },
* // { name: "fetch__fetch_url", description: "...", ... }
* // ]
*
* // Get tools from specific servers only
* const someTools = await client.getToolSchemas({ servers: ['time', 'fetch'] });
* const someTools = await client.getTools({ servers: ['time', 'fetch'] });
*
* // Original tool name "get_current_time" becomes "time__get_current_time"
* // This prevents clashes if multiple servers have tools with the same name
* ```
*/
async getToolSchemas(options?: { servers?: string[] }): Promise<Tool[]> {
async getTools(options?: { servers?: string[] }): Promise<Tool[]> {
const { servers } = options || {};

// Get healthy servers (fetches list if not provided, then filters by health).
Expand All @@ -334,10 +334,8 @@ export class McpdClient {
name: `${serverName}__${tool.name}`,
});
}
} else {
// If we can't get tools for a server, skip it with a warning
console.warn(`Failed to get tools for server:`, result.reason);
}
// Silently skip failed servers - they're already filtered by health checks
}

return allTools;
Expand Down Expand Up @@ -405,10 +403,9 @@ export class McpdClient {
...prompt,
name: `${serverName}__${prompt.name}`,
}));
} else {
console.warn(`Failed to get prompts for server:`, result.reason);
return []; // Return an empty array for rejected promises
}
// Silently skip failed servers - they're already filtered by health checks
return [];
});

return allPrompts;
Expand Down Expand Up @@ -550,10 +547,9 @@ export class McpdClient {

return namespacedResource;
});
} else {
console.warn(`Failed to get resources for server:`, result.reason);
return [];
}
// Silently skip failed servers - they're already filtered by health checks
return [];
});

return allResources;
Expand Down Expand Up @@ -624,13 +620,9 @@ export class McpdClient {
_serverName: serverName,
_templateName: template.name,
}));
} else {
console.warn(
`Failed to get resource templates for server:`,
result.reason,
);
return [];
}
// Silently skip failed servers - they're already filtered by health checks
return [];
});

return allTemplates;
Expand Down Expand Up @@ -1165,10 +1157,8 @@ export class McpdClient {
);
agentTools.push(func);
}
} else {
// If we can't get tools for a server, skip it with a warning
console.warn(`Failed to get tools for server:`, result.reason);
}
// Silently skip failed servers - they're already filtered by health checks
}

return agentTools;
Expand Down
12 changes: 6 additions & 6 deletions src/dynamicCaller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export class ServersNamespace {
* const timeServer = client.servers.time; // Returns Server(...)
*
* // List available tools
* const tools = await timeServer.listTools();
* const tools = await timeServer.getTools();
*
* // Call tools through the .tools namespace:
* await timeServer.tools.get_current_time({ timezone: "UTC" })
Expand Down Expand Up @@ -196,21 +196,21 @@ export class Server {
}

/**
* List all tools available on this server.
* Get all tools available on this server.
*
* @returns Array of tool schemas
* @throws {ServerNotFoundError} If the server doesn't exist
* @throws {ServerUnhealthyError} If the server is unhealthy
*
* @example
* ```typescript
* const tools = await client.servers.time.listTools();
* const tools = await client.servers.time.getTools();
* for (const tool of tools) {
* console.log(`${tool.name}: ${tool.description}`);
* }
* ```
*/
async listTools(): Promise<Tool[]> {
async getTools(): Promise<Tool[]> {
return this.#getTools(this.#serverName);
}

Expand Down Expand Up @@ -277,7 +277,7 @@ export class Server {
if (!tool) {
throw new ToolNotFoundError(
`Tool '${toolName}' not found on server '${this.#serverName}'. ` +
`Use client.servers.${this.#serverName}.listTools() to see available tools.`,
`Use client.servers.${this.#serverName}.getTools() to see available tools.`,
this.#serverName,
toolName,
);
Expand Down Expand Up @@ -542,7 +542,7 @@ export class ToolsNamespace {
if (!tool) {
throw new ToolNotFoundError(
`Tool '${toolName}' not found on server '${target.#serverName}'. ` +
`Use client.servers.${target.#serverName}.listTools() to see available tools.`,
`Use client.servers.${target.#serverName}.getTools() to see available tools.`,
target.#serverName,
toolName,
);
Expand Down
16 changes: 8 additions & 8 deletions tests/unit/apiSurface.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ describe("API Surface - Complete Test Coverage", () => {
expect(isHealthy).toBe(true);
});

it("client.servers.foo.listTools()", async () => {
it("client.servers.foo.getTools()", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({ status: "ok" }),
Expand All @@ -82,11 +82,11 @@ describe("API Surface - Complete Test Coverage", () => {
json: async () => ({ tools: [{ name: "tool1" }] }),
});

const tools = await client.servers.time!.listTools();
const tools = await client.servers.time!.getTools();
expect(tools).toHaveLength(1);
});

it('client.servers["foo"].listTools()', async () => {
it('client.servers["foo"].getTools()', async () => {
const serverName = "time";
mockFetch.mockResolvedValueOnce({
ok: true,
Expand All @@ -97,7 +97,7 @@ describe("API Surface - Complete Test Coverage", () => {
json: async () => ({ tools: [{ name: "tool1" }] }),
});

const tools = await client.servers[serverName]!.listTools();
const tools = await client.servers[serverName]!.getTools();
expect(tools).toHaveLength(1);
});

Expand Down Expand Up @@ -243,7 +243,7 @@ describe("API Surface - Complete Test Coverage", () => {
expect(result).toEqual({ result: "12:00" });
});

it("client.getToolSchemas() - no options", async () => {
it("client.getTools() - no options", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ["time"],
Expand All @@ -261,11 +261,11 @@ describe("API Surface - Complete Test Coverage", () => {
}),
});

const schemas = await client.getToolSchemas();
const schemas = await client.getTools();
expect(schemas[0]?.name).toBe("time__get_time");
});

it("client.getToolSchemas(options) - with servers filter", async () => {
it("client.getTools(options) - with servers filter", async () => {
mockFetch.mockResolvedValueOnce({
ok: true,
json: async () => ({
Expand All @@ -279,7 +279,7 @@ describe("API Surface - Complete Test Coverage", () => {
}),
});

const schemas = await client.getToolSchemas({ servers: ["time"] });
const schemas = await client.getTools({ servers: ["time"] });
expect(schemas[0]?.name).toBe("time__get_time");
});

Expand Down
10 changes: 5 additions & 5 deletions tests/unit/client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ describe("McpdClient", () => {
});
});

describe("getToolSchemas()", () => {
describe("getTools()", () => {
it("should return all tools from all servers with transformed names", async () => {
const mockTools = {
time: [
Expand Down Expand Up @@ -186,7 +186,7 @@ describe("McpdClient", () => {
json: async () => ({ tools: mockTools.math }),
});

const tools = await client.getToolSchemas();
const tools = await client.getTools();

expect(tools).toHaveLength(3);
expect(tools[0]?.name).toBe("time__get_current_time");
Expand Down Expand Up @@ -227,7 +227,7 @@ describe("McpdClient", () => {
json: async () => ({ tools: mockTools.time }),
});

const tools = await client.getToolSchemas({ servers: ["time"] });
const tools = await client.getTools({ servers: ["time"] });

expect(tools).toHaveLength(1);
expect(tools[0]?.name).toBe("time__get_current_time");
Expand All @@ -248,7 +248,7 @@ describe("McpdClient", () => {
}),
});

const tools = await client.getToolSchemas();
const tools = await client.getTools();

expect(tools).toHaveLength(0);
});
Expand Down Expand Up @@ -298,7 +298,7 @@ describe("McpdClient", () => {
json: async () => ({ tools: mockTools.time }),
});

const tools = await client.getToolSchemas();
const tools = await client.getTools();

// Should only get tools from healthy server
expect(tools).toHaveLength(1);
Expand Down
10 changes: 5 additions & 5 deletions tests/unit/dynamicCaller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ToolNotFoundError } from "../../src/errors";
*
* These tests ensure that all documented API patterns work correctly:
* - client.servers[serverName]! (dynamic server access)
* - client.servers.foo.listTools() (list tools)
* - client.servers.foo.getTools() (list tools)
* - client.servers.foo!.tools.bar!(args) (static tool call)
* - client.servers.foo.callTool(name, args) (dynamic tool call)
* - client.servers.foo.hasTool(name) (check tool existence)
Expand Down Expand Up @@ -61,14 +61,14 @@ describe("Dynamic Calling Patterns", () => {
}),
});

const tools = await client.servers[serverName]!.listTools();
const tools = await client.servers[serverName]!.getTools();

expect(tools).toHaveLength(1);
expect(tools[0]?.name).toBe("get_current_time");
});
});

describe("Pattern: client.servers.foo.listTools()", () => {
describe("Pattern: client.servers.foo.getTools()", () => {
it("should list tools with static property access", async () => {
// Health check.
mockFetch.mockResolvedValueOnce({
Expand All @@ -92,7 +92,7 @@ describe("Dynamic Calling Patterns", () => {
}),
});

const tools = await client.servers.time!.listTools();
const tools = await client.servers.time!.getTools();

expect(tools).toHaveLength(2);
expect(tools[0]?.name).toBe("tool1");
Expand Down Expand Up @@ -473,7 +473,7 @@ describe("Dynamic Calling Patterns", () => {
});

// Mix dynamic server with static method.
const tools = await client.servers[serverName]!.listTools();
const tools = await client.servers[serverName]!.getTools();

expect(tools).toHaveLength(1);
expect(tools[0]?.name).toBe("tool1");
Expand Down