@mcptoolgate/client 1.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.
- package/README.md +106 -0
- package/dist/api.d.ts +29 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +61 -0
- package/dist/api.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +114 -0
- package/dist/index.js.map +1 -0
- package/package.json +35 -0
- package/src/api.ts +78 -0
- package/src/index.ts +134 -0
- package/tsconfig.json +24 -0
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# MCP Tool Gate Client
|
|
2
|
+
|
|
3
|
+
Lightweight MCP client for integrating MCP Tool Gate with Claude Desktop and other MCP clients.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Quick Start (npx)
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"mcptoolgate": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["-y", "@mcptoolgate/client"],
|
|
15
|
+
"env": {
|
|
16
|
+
"MCPTOOLGATE_API_KEY": "your-api-key-here"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Local Development
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Install dependencies
|
|
27
|
+
npm install
|
|
28
|
+
|
|
29
|
+
# Build the client
|
|
30
|
+
npm run build
|
|
31
|
+
|
|
32
|
+
# Link for local testing
|
|
33
|
+
npm link
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
The client requires two environment variables:
|
|
39
|
+
|
|
40
|
+
- **MCPTOOLGATE_API_KEY** (required): Your API key from the MCP Tool Gate dashboard
|
|
41
|
+
- **MCPTOOLGATE_URL** (optional): Backend URL (defaults to production)
|
|
42
|
+
|
|
43
|
+
## Usage with Claude Desktop
|
|
44
|
+
|
|
45
|
+
1. **Generate API Key:**
|
|
46
|
+
- Log in to your MCP Tool Gate dashboard
|
|
47
|
+
- Go to Settings → API Keys
|
|
48
|
+
- Click "Generate New Key"
|
|
49
|
+
- Copy the key (shown only once!)
|
|
50
|
+
|
|
51
|
+
2. **Configure Claude Desktop:**
|
|
52
|
+
|
|
53
|
+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"mcptoolgate": {
|
|
59
|
+
"command": "npx",
|
|
60
|
+
"args": ["-y", "@mcptoolgate/client"],
|
|
61
|
+
"env": {
|
|
62
|
+
"MCPTOOLGATE_API_KEY": "mgk_your_key_here"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
3. **Restart Claude Desktop**
|
|
70
|
+
|
|
71
|
+
4. **Start using your tools!**
|
|
72
|
+
- Your configured tools will appear automatically
|
|
73
|
+
- Destructive actions will require approval
|
|
74
|
+
- Check your dashboard for approval requests
|
|
75
|
+
|
|
76
|
+
## Features
|
|
77
|
+
|
|
78
|
+
- ✅ **Zero Configuration**: Just add your API key
|
|
79
|
+
- ✅ **Automatic Tool Discovery**: Tools from your dashboard appear instantly
|
|
80
|
+
- ✅ **Policy Enforcement**: Backend applies all your configured policies
|
|
81
|
+
- ✅ **Approval Workflows**: Destructive actions pause for human review
|
|
82
|
+
- ✅ **Real-time**: No caching, always up-to-date
|
|
83
|
+
|
|
84
|
+
## Troubleshooting
|
|
85
|
+
|
|
86
|
+
### Tools not appearing?
|
|
87
|
+
|
|
88
|
+
1. Check your API key is correct
|
|
89
|
+
2. Verify the key isn't revoked in the dashboard
|
|
90
|
+
3. Check Claude Desktop logs: `tail -f ~/Library/Logs/Claude/mcp*.log`
|
|
91
|
+
|
|
92
|
+
### Execution failing?
|
|
93
|
+
|
|
94
|
+
1. Check tool adapter configuration in dashboard
|
|
95
|
+
2. Verify credentials (Slack webhooks, GitHub tokens, etc.)
|
|
96
|
+
3. Check audit logs in dashboard for error details
|
|
97
|
+
|
|
98
|
+
## Support
|
|
99
|
+
|
|
100
|
+
- Dashboard: https://your-dashboard-url.com
|
|
101
|
+
- Documentation: https://docs.mcptoolgate.com
|
|
102
|
+
- Issues: https://github.com/your-org/mcp-tool-gate/issues
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface Tool {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: any;
|
|
5
|
+
}
|
|
6
|
+
export interface ExecutionResult {
|
|
7
|
+
status: 'completed' | 'pending_approval' | 'denied' | 'failed';
|
|
8
|
+
result?: any;
|
|
9
|
+
approval_request_id?: string;
|
|
10
|
+
message?: string;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare class MCPToolGateAPI {
|
|
14
|
+
private client;
|
|
15
|
+
constructor(apiKey: string, baseURL: string);
|
|
16
|
+
/**
|
|
17
|
+
* List all available tools for the authenticated tenant
|
|
18
|
+
*/
|
|
19
|
+
listTools(): Promise<Tool[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Execute a tool with given input
|
|
22
|
+
*/
|
|
23
|
+
executeTool(toolName: string, input: any): Promise<ExecutionResult>;
|
|
24
|
+
/**
|
|
25
|
+
* Check approval status for a pending request
|
|
26
|
+
*/
|
|
27
|
+
checkApprovalStatus(requestId: string): Promise<any>;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,IAAI;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC5B,MAAM,EAAE,WAAW,GAAG,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC/D,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,cAAc;IACvB,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;IAW3C;;OAEG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IAUlC;;OAEG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAAC,eAAe,CAAC;IAmBzE;;OAEG;IACG,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;CAS7D"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
export class MCPToolGateAPI {
|
|
3
|
+
client;
|
|
4
|
+
constructor(apiKey, baseURL) {
|
|
5
|
+
this.client = axios.create({
|
|
6
|
+
baseURL,
|
|
7
|
+
headers: {
|
|
8
|
+
'x-api-key': apiKey,
|
|
9
|
+
'Content-Type': 'application/json',
|
|
10
|
+
},
|
|
11
|
+
timeout: 30000, // 30 second timeout
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* List all available tools for the authenticated tenant
|
|
16
|
+
*/
|
|
17
|
+
async listTools() {
|
|
18
|
+
try {
|
|
19
|
+
const response = await this.client.get('/v1/mcp/tools');
|
|
20
|
+
return response.data.tools || [];
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.error('[MCP Tool Gate API] Error listing tools:', error.message);
|
|
24
|
+
throw new Error(`Failed to list tools: ${error.response?.data?.error || error.message}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Execute a tool with given input
|
|
29
|
+
*/
|
|
30
|
+
async executeTool(toolName, input) {
|
|
31
|
+
try {
|
|
32
|
+
const response = await this.client.post('/v1/mcp/execute', {
|
|
33
|
+
tool: toolName,
|
|
34
|
+
input,
|
|
35
|
+
});
|
|
36
|
+
return response.data;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
console.error('[MCP Tool Gate API] Error executing tool:', error.message);
|
|
40
|
+
// Return failed status instead of throwing
|
|
41
|
+
return {
|
|
42
|
+
status: 'failed',
|
|
43
|
+
error: error.response?.data?.error || error.message,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Check approval status for a pending request
|
|
49
|
+
*/
|
|
50
|
+
async checkApprovalStatus(requestId) {
|
|
51
|
+
try {
|
|
52
|
+
const response = await this.client.get(`/v1/mcp/approvals/${requestId}`);
|
|
53
|
+
return response.data;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error('[MCP Tool Gate API] Error checking approval:', error.message);
|
|
57
|
+
throw new Error(`Failed to check approval: ${error.response?.data?.error || error.message}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAwB,MAAM,OAAO,CAAC;AAgB7C,MAAM,OAAO,cAAc;IACf,MAAM,CAAgB;IAE9B,YAAY,MAAc,EAAE,OAAe;QACvC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;YACvB,OAAO;YACP,OAAO,EAAE;gBACL,WAAW,EAAE,MAAM;gBACnB,cAAc,EAAE,kBAAkB;aACrC;YACD,OAAO,EAAE,KAAK,EAAE,oBAAoB;SACvC,CAAC,CAAC;IACP,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS;QACX,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YACxD,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QACrC,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YACzE,MAAM,IAAI,KAAK,CAAC,yBAAyB,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7F,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,WAAW,CAAC,QAAgB,EAAE,KAAU;QAC1C,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE;gBACvD,IAAI,EAAE,QAAQ;gBACd,KAAK;aACR,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC,IAAI,CAAC;QACzB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAE1E,2CAA2C;YAC3C,OAAO;gBACH,MAAM,EAAE,QAAQ;gBAChB,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK,CAAC,OAAO;aACtD,CAAC;QACN,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB,CAAC,SAAiB;QACvC,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,qBAAqB,SAAS,EAAE,CAAC,CAAC;YACzE,OAAO,QAAQ,CAAC,IAAI,CAAC;QACzB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,8CAA8C,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAC7E,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACjG,CAAC;IACL,CAAC;CACJ"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
import { MCPToolGateAPI } from './api.js';
|
|
6
|
+
// Get configuration from environment
|
|
7
|
+
const API_KEY = process.env.MCPTOOLGATE_API_KEY;
|
|
8
|
+
const API_URL = process.env.MCPTOOLGATE_URL || 'https://app.mcptoolgate.com';
|
|
9
|
+
if (!API_KEY) {
|
|
10
|
+
console.error('Error: MCPTOOLGATE_API_KEY environment variable is required');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
// Initialize API client
|
|
14
|
+
const api = new MCPToolGateAPI(API_KEY, API_URL);
|
|
15
|
+
// Create MCP server
|
|
16
|
+
const server = new Server({
|
|
17
|
+
name: 'mcptoolgate',
|
|
18
|
+
version: '1.0.0',
|
|
19
|
+
}, {
|
|
20
|
+
capabilities: {
|
|
21
|
+
tools: {},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
// Handle tool listing
|
|
25
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
26
|
+
try {
|
|
27
|
+
const tools = await api.listTools();
|
|
28
|
+
return {
|
|
29
|
+
tools: tools.map((tool) => ({
|
|
30
|
+
name: tool.name,
|
|
31
|
+
description: tool.description,
|
|
32
|
+
inputSchema: tool.inputSchema,
|
|
33
|
+
})),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error('Error listing tools:', error);
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
// Handle tool execution
|
|
42
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
43
|
+
try {
|
|
44
|
+
const { name, arguments: args } = request.params;
|
|
45
|
+
console.error(`[MCP Tool Gate] Executing tool: ${name}`);
|
|
46
|
+
const result = await api.executeTool(name, args || {});
|
|
47
|
+
// Handle different execution statuses
|
|
48
|
+
if (result.status === 'pending_approval') {
|
|
49
|
+
return {
|
|
50
|
+
content: [
|
|
51
|
+
{
|
|
52
|
+
type: 'text',
|
|
53
|
+
text: `⏸️ Tool execution paused - approval required.\n\nApproval Request ID: ${result.approval_request_id}\n\nPlease check your MCP Tool Gate dashboard to approve or deny this request.`,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (result.status === 'denied') {
|
|
59
|
+
return {
|
|
60
|
+
content: [
|
|
61
|
+
{
|
|
62
|
+
type: 'text',
|
|
63
|
+
text: `❌ Tool execution denied by policy.\n\n${result.message || 'This action is not allowed.'}`,
|
|
64
|
+
},
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if (result.status === 'failed') {
|
|
69
|
+
return {
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
72
|
+
type: 'text',
|
|
73
|
+
text: `❌ Tool execution failed.\n\n${result.error || 'An error occurred during execution.'}`,
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
isError: true,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// Success
|
|
80
|
+
return {
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: 'text',
|
|
84
|
+
text: typeof result.result === 'string'
|
|
85
|
+
? result.result
|
|
86
|
+
: JSON.stringify(result.result, null, 2),
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
console.error('[MCP Tool Gate] Tool execution error:', error);
|
|
93
|
+
return {
|
|
94
|
+
content: [
|
|
95
|
+
{
|
|
96
|
+
type: 'text',
|
|
97
|
+
text: `Error: ${error.message || 'Tool execution failed'}`,
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
isError: true,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
// Start server
|
|
105
|
+
async function main() {
|
|
106
|
+
const transport = new StdioServerTransport();
|
|
107
|
+
await server.connect(transport);
|
|
108
|
+
console.error('[MCP Tool Gate] Client connected to', API_URL);
|
|
109
|
+
}
|
|
110
|
+
main().catch((error) => {
|
|
111
|
+
console.error('[MCP Tool Gate] Fatal error:', error);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
});
|
|
114
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mcptoolgate/client",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP Tool Gate client for Claude Desktop - secure MCP tool governance",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcptoolgate-client": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"claude",
|
|
18
|
+
"security",
|
|
19
|
+
"governance",
|
|
20
|
+
"approval"
|
|
21
|
+
],
|
|
22
|
+
"author": "MCP Tool Gate",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@modelcontextprotocol/sdk": "^0.5.0",
|
|
26
|
+
"axios": "^1.6.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^20.0.0",
|
|
30
|
+
"typescript": "^5.3.0"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/api.ts
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import axios, { AxiosInstance } from 'axios';
|
|
2
|
+
|
|
3
|
+
export interface Tool {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: any;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ExecutionResult {
|
|
10
|
+
status: 'completed' | 'pending_approval' | 'denied' | 'failed';
|
|
11
|
+
result?: any;
|
|
12
|
+
approval_request_id?: string;
|
|
13
|
+
message?: string;
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class MCPToolGateAPI {
|
|
18
|
+
private client: AxiosInstance;
|
|
19
|
+
|
|
20
|
+
constructor(apiKey: string, baseURL: string) {
|
|
21
|
+
this.client = axios.create({
|
|
22
|
+
baseURL,
|
|
23
|
+
headers: {
|
|
24
|
+
'x-api-key': apiKey,
|
|
25
|
+
'Content-Type': 'application/json',
|
|
26
|
+
},
|
|
27
|
+
timeout: 30000, // 30 second timeout
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* List all available tools for the authenticated tenant
|
|
33
|
+
*/
|
|
34
|
+
async listTools(): Promise<Tool[]> {
|
|
35
|
+
try {
|
|
36
|
+
const response = await this.client.get('/v1/mcp/tools');
|
|
37
|
+
return response.data.tools || [];
|
|
38
|
+
} catch (error: any) {
|
|
39
|
+
console.error('[MCP Tool Gate API] Error listing tools:', error.message);
|
|
40
|
+
throw new Error(`Failed to list tools: ${error.response?.data?.error || error.message}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Execute a tool with given input
|
|
46
|
+
*/
|
|
47
|
+
async executeTool(toolName: string, input: any): Promise<ExecutionResult> {
|
|
48
|
+
try {
|
|
49
|
+
const response = await this.client.post('/v1/mcp/execute', {
|
|
50
|
+
tool: toolName,
|
|
51
|
+
input,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return response.data;
|
|
55
|
+
} catch (error: any) {
|
|
56
|
+
console.error('[MCP Tool Gate API] Error executing tool:', error.message);
|
|
57
|
+
|
|
58
|
+
// Return failed status instead of throwing
|
|
59
|
+
return {
|
|
60
|
+
status: 'failed',
|
|
61
|
+
error: error.response?.data?.error || error.message,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Check approval status for a pending request
|
|
68
|
+
*/
|
|
69
|
+
async checkApprovalStatus(requestId: string): Promise<any> {
|
|
70
|
+
try {
|
|
71
|
+
const response = await this.client.get(`/v1/mcp/approvals/${requestId}`);
|
|
72
|
+
return response.data;
|
|
73
|
+
} catch (error: any) {
|
|
74
|
+
console.error('[MCP Tool Gate API] Error checking approval:', error.message);
|
|
75
|
+
throw new Error(`Failed to check approval: ${error.response?.data?.error || error.message}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
|
+
import {
|
|
6
|
+
CallToolRequestSchema,
|
|
7
|
+
ListToolsRequestSchema,
|
|
8
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
+
import { MCPToolGateAPI } from './api.js';
|
|
10
|
+
|
|
11
|
+
// Get configuration from environment
|
|
12
|
+
const API_KEY = process.env.MCPTOOLGATE_API_KEY;
|
|
13
|
+
const API_URL = process.env.MCPTOOLGATE_URL || 'https://app.mcptoolgate.com';
|
|
14
|
+
|
|
15
|
+
if (!API_KEY) {
|
|
16
|
+
console.error('Error: MCPTOOLGATE_API_KEY environment variable is required');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Initialize API client
|
|
21
|
+
const api = new MCPToolGateAPI(API_KEY, API_URL);
|
|
22
|
+
|
|
23
|
+
// Create MCP server
|
|
24
|
+
const server = new Server(
|
|
25
|
+
{
|
|
26
|
+
name: 'mcptoolgate',
|
|
27
|
+
version: '1.0.0',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
capabilities: {
|
|
31
|
+
tools: {},
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
// Handle tool listing
|
|
37
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
38
|
+
try {
|
|
39
|
+
const tools = await api.listTools();
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
tools: tools.map((tool: any) => ({
|
|
43
|
+
name: tool.name,
|
|
44
|
+
description: tool.description,
|
|
45
|
+
inputSchema: tool.inputSchema,
|
|
46
|
+
})),
|
|
47
|
+
};
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error('Error listing tools:', error);
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Handle tool execution
|
|
55
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
56
|
+
try {
|
|
57
|
+
const { name, arguments: args } = request.params;
|
|
58
|
+
|
|
59
|
+
console.error(`[MCP Tool Gate] Executing tool: ${name}`);
|
|
60
|
+
|
|
61
|
+
const result = await api.executeTool(name, args || {});
|
|
62
|
+
|
|
63
|
+
// Handle different execution statuses
|
|
64
|
+
if (result.status === 'pending_approval') {
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: 'text',
|
|
69
|
+
text: `⏸️ Tool execution paused - approval required.\n\nApproval Request ID: ${result.approval_request_id}\n\nPlease check your MCP Tool Gate dashboard to approve or deny this request.`,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (result.status === 'denied') {
|
|
76
|
+
return {
|
|
77
|
+
content: [
|
|
78
|
+
{
|
|
79
|
+
type: 'text',
|
|
80
|
+
text: `❌ Tool execution denied by policy.\n\n${result.message || 'This action is not allowed.'}`,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (result.status === 'failed') {
|
|
87
|
+
return {
|
|
88
|
+
content: [
|
|
89
|
+
{
|
|
90
|
+
type: 'text',
|
|
91
|
+
text: `❌ Tool execution failed.\n\n${result.error || 'An error occurred during execution.'}`,
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
isError: true,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Success
|
|
99
|
+
return {
|
|
100
|
+
content: [
|
|
101
|
+
{
|
|
102
|
+
type: 'text',
|
|
103
|
+
text: typeof result.result === 'string'
|
|
104
|
+
? result.result
|
|
105
|
+
: JSON.stringify(result.result, null, 2),
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
} catch (error: any) {
|
|
110
|
+
console.error('[MCP Tool Gate] Tool execution error:', error);
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
content: [
|
|
114
|
+
{
|
|
115
|
+
type: 'text',
|
|
116
|
+
text: `Error: ${error.message || 'Tool execution failed'}`,
|
|
117
|
+
},
|
|
118
|
+
],
|
|
119
|
+
isError: true,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Start server
|
|
125
|
+
async function main() {
|
|
126
|
+
const transport = new StdioServerTransport();
|
|
127
|
+
await server.connect(transport);
|
|
128
|
+
console.error('[MCP Tool Gate] Client connected to', API_URL);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
main().catch((error) => {
|
|
132
|
+
console.error('[MCP Tool Gate] Fatal error:', error);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"declaration": true,
|
|
14
|
+
"declarationMap": true,
|
|
15
|
+
"sourceMap": true
|
|
16
|
+
},
|
|
17
|
+
"include": [
|
|
18
|
+
"src/**/*"
|
|
19
|
+
],
|
|
20
|
+
"exclude": [
|
|
21
|
+
"node_modules",
|
|
22
|
+
"dist"
|
|
23
|
+
]
|
|
24
|
+
}
|