kojee-mcp 0.1.0 → 0.1.1
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/dist/{chunk-UDF4BJS5.js → chunk-TJNNT7XM.js} +208 -104
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +14 -4
|
@@ -517,137 +517,124 @@ function sleep(ms) {
|
|
|
517
517
|
}
|
|
518
518
|
|
|
519
519
|
// src/tool-registry.ts
|
|
520
|
-
var
|
|
521
|
-
|
|
520
|
+
var BUILTIN_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
521
|
+
"kojee_check_approval",
|
|
522
|
+
"kojee_revoke_request",
|
|
523
|
+
"kojee_send_feedback"
|
|
524
|
+
]);
|
|
525
|
+
function extractConnector(toolName) {
|
|
526
|
+
if (BUILTIN_TOOL_NAMES.has(toolName)) return null;
|
|
527
|
+
const idx = toolName.indexOf("_");
|
|
528
|
+
if (idx === -1) return null;
|
|
529
|
+
return toolName.substring(0, idx);
|
|
530
|
+
}
|
|
522
531
|
var ToolRegistry = class {
|
|
523
532
|
constructor(gateway) {
|
|
524
533
|
this.gateway = gateway;
|
|
525
534
|
}
|
|
526
535
|
gateway;
|
|
527
|
-
/**
|
|
528
|
-
|
|
529
|
-
/**
|
|
530
|
-
|
|
536
|
+
/** Connector ID → connector info with tool list */
|
|
537
|
+
connectors = /* @__PURE__ */ new Map();
|
|
538
|
+
/** All tool names (flat) for validation */
|
|
539
|
+
allToolNames = /* @__PURE__ */ new Set();
|
|
531
540
|
/**
|
|
532
|
-
*
|
|
533
|
-
* 1. Call tools/list (lean) — returns names + descriptions for all tools.
|
|
534
|
-
* 2. Separate built-in kojee_* tools (already prefixed) from connector tools.
|
|
535
|
-
* 3. Call tools/get_schema for connector tool names to get full inputSchema.
|
|
536
|
-
* 4. Register everything with the kojee_ prefix mapping.
|
|
541
|
+
* Fetch the lean tool list from the gateway and group by connector.
|
|
537
542
|
*/
|
|
538
543
|
async discoverTools() {
|
|
539
|
-
console.error("[tools] Fetching tool list from gateway...");
|
|
544
|
+
console.error("[tools] Fetching lean tool list from gateway...");
|
|
540
545
|
const listResult = await this.gateway.sendRpc("tools/list", {});
|
|
541
546
|
const toolList = listResult?.tools;
|
|
542
547
|
if (!toolList || !Array.isArray(toolList)) {
|
|
543
548
|
console.error("[tools] No tools returned from gateway");
|
|
544
549
|
return;
|
|
545
550
|
}
|
|
546
|
-
console.error(`[tools] Found ${toolList.length} tools`);
|
|
547
|
-
const builtinTools = [];
|
|
548
|
-
const connectorToolNames = [];
|
|
549
551
|
for (const tool of toolList) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
const builtinSchemaResult = await this.gateway.sendRpc("tools/get_schema", {
|
|
558
|
-
names: builtinTools.map((t) => t.name)
|
|
559
|
-
});
|
|
560
|
-
const fullBuiltins = builtinSchemaResult?.tools;
|
|
561
|
-
if (fullBuiltins && Array.isArray(fullBuiltins)) {
|
|
562
|
-
for (const tool of fullBuiltins) {
|
|
563
|
-
this.registerTool(tool);
|
|
564
|
-
}
|
|
565
|
-
} else {
|
|
566
|
-
for (const tool of builtinTools) {
|
|
567
|
-
this.registerTool({
|
|
568
|
-
name: tool.name,
|
|
569
|
-
description: tool.description,
|
|
570
|
-
inputSchema: tool.inputSchema ?? { type: "object", properties: {} }
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
if (connectorToolNames.length > 0) {
|
|
576
|
-
console.error(`[tools] Fetching schemas for ${connectorToolNames.length} connector tools...`);
|
|
577
|
-
const schemaResult = await this.gateway.sendRpc("tools/get_schema", {
|
|
578
|
-
names: connectorToolNames
|
|
579
|
-
});
|
|
580
|
-
const fullTools = schemaResult?.tools;
|
|
581
|
-
const notFound = schemaResult?.not_found;
|
|
582
|
-
if (notFound && notFound.length > 0) {
|
|
583
|
-
console.error(`[tools] Warning: schemas not found for: ${notFound.join(", ")}`);
|
|
584
|
-
}
|
|
585
|
-
if (fullTools && Array.isArray(fullTools)) {
|
|
586
|
-
for (const tool of fullTools) {
|
|
587
|
-
this.registerTool(tool);
|
|
588
|
-
}
|
|
589
|
-
} else {
|
|
590
|
-
console.error("[tools] Schema fetch failed, using lean definitions");
|
|
591
|
-
for (const name of connectorToolNames) {
|
|
592
|
-
const lean = toolList.find((t) => t.name === name);
|
|
593
|
-
if (lean) {
|
|
594
|
-
this.registerTool({
|
|
595
|
-
name: lean.name,
|
|
596
|
-
description: lean.description,
|
|
597
|
-
inputSchema: { type: "object", properties: {} }
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
}
|
|
552
|
+
this.allToolNames.add(tool.name);
|
|
553
|
+
const connector = extractConnector(tool.name);
|
|
554
|
+
if (!connector) continue;
|
|
555
|
+
let info = this.connectors.get(connector);
|
|
556
|
+
if (!info) {
|
|
557
|
+
info = { id: connector, tools: [] };
|
|
558
|
+
this.connectors.set(connector, info);
|
|
601
559
|
}
|
|
560
|
+
info.tools.push({ name: tool.name, description: tool.description });
|
|
602
561
|
}
|
|
603
|
-
console.error(
|
|
562
|
+
console.error(
|
|
563
|
+
`[tools] Discovered ${this.allToolNames.size} tools across ${this.connectors.size} connectors`
|
|
564
|
+
);
|
|
604
565
|
}
|
|
605
566
|
/**
|
|
606
|
-
*
|
|
567
|
+
* Get the list of connector meta-tools to register with the MCP server.
|
|
568
|
+
* Each connector becomes a tool like "kojee_gmail" whose description
|
|
569
|
+
* lists its available tools.
|
|
607
570
|
*/
|
|
608
|
-
|
|
609
|
-
const
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
571
|
+
getConnectorTools() {
|
|
572
|
+
const tools = [];
|
|
573
|
+
for (const [connectorId, info] of this.connectors) {
|
|
574
|
+
const toolNames = info.tools.map((t) => t.name).join(", ");
|
|
575
|
+
tools.push({
|
|
576
|
+
name: `kojee_${connectorId}`,
|
|
577
|
+
description: `${connectorId} tools available via Kojee (${info.tools.length} tools: ${toolNames}). Call this tool to see descriptions and details for each.`,
|
|
578
|
+
inputSchema: { type: "object", properties: {} }
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
return tools;
|
|
616
582
|
}
|
|
617
583
|
/**
|
|
618
|
-
* Get
|
|
584
|
+
* Get the detailed tool list for a specific connector.
|
|
619
585
|
*/
|
|
620
|
-
|
|
621
|
-
|
|
586
|
+
getConnectorToolList(connectorId) {
|
|
587
|
+
const info = this.connectors.get(connectorId);
|
|
588
|
+
if (!info) {
|
|
589
|
+
return `No connector '${connectorId}' found. Available: ${Array.from(this.connectors.keys()).join(", ")}`;
|
|
590
|
+
}
|
|
591
|
+
const lines = info.tools.map((t) => `- **${t.name}**: ${t.description}`);
|
|
592
|
+
return `## ${connectorId} tools
|
|
593
|
+
|
|
594
|
+
${lines.join("\n")}
|
|
595
|
+
|
|
596
|
+
Use kojee_get_tool_schema to get the full input schema, then kojee_call_tool to execute.`;
|
|
622
597
|
}
|
|
623
598
|
/**
|
|
624
|
-
*
|
|
625
|
-
* Returns null if the tool is not registered.
|
|
599
|
+
* Get full schemas for specific tools via tools/get_schema.
|
|
626
600
|
*/
|
|
627
|
-
|
|
628
|
-
|
|
601
|
+
async getToolSchemas(names) {
|
|
602
|
+
const result = await this.gateway.sendRpc("tools/get_schema", { names });
|
|
603
|
+
const response = result;
|
|
604
|
+
if (response.not_found && response.not_found.length > 0) {
|
|
605
|
+
console.error(`[tools] Schemas not found for: ${response.not_found.join(", ")}`);
|
|
606
|
+
}
|
|
607
|
+
return response.tools ?? [];
|
|
629
608
|
}
|
|
630
609
|
/**
|
|
631
|
-
* Call a tool through the gateway
|
|
610
|
+
* Call a tool through the gateway.
|
|
632
611
|
*/
|
|
633
|
-
async callTool(
|
|
634
|
-
|
|
635
|
-
|
|
612
|
+
async callTool(name, args) {
|
|
613
|
+
if (!this.allToolNames.has(name)) {
|
|
614
|
+
const available = Array.from(this.connectors.keys()).map((c) => `kojee_${c}`).join(", ");
|
|
636
615
|
return {
|
|
637
616
|
content: [
|
|
638
617
|
{
|
|
639
618
|
type: "text",
|
|
640
|
-
text: `Tool '${
|
|
619
|
+
text: `Tool '${name}' not found. Use one of the connector tools (${available}) to discover available tools.`
|
|
641
620
|
}
|
|
642
621
|
],
|
|
643
622
|
isError: true
|
|
644
623
|
};
|
|
645
624
|
}
|
|
646
625
|
return this.gateway.sendRpc("tools/call", {
|
|
647
|
-
name
|
|
626
|
+
name,
|
|
648
627
|
arguments: args
|
|
649
628
|
});
|
|
650
629
|
}
|
|
630
|
+
/** List of connector IDs. */
|
|
631
|
+
get connectorIds() {
|
|
632
|
+
return Array.from(this.connectors.keys());
|
|
633
|
+
}
|
|
634
|
+
/** Total number of discovered tools. */
|
|
635
|
+
get toolCount() {
|
|
636
|
+
return this.allToolNames.size;
|
|
637
|
+
}
|
|
651
638
|
};
|
|
652
639
|
|
|
653
640
|
// src/server.ts
|
|
@@ -657,11 +644,80 @@ import {
|
|
|
657
644
|
ListToolsRequestSchema,
|
|
658
645
|
CallToolRequestSchema
|
|
659
646
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
647
|
+
var CONNECTOR_TOOL_PREFIX = "kojee_";
|
|
648
|
+
var UTILITY_TOOLS = [
|
|
649
|
+
{
|
|
650
|
+
name: "kojee_get_tool_schema",
|
|
651
|
+
description: "Get the full input schema for one or more Kojee tools. Call this before kojee_call_tool to know the exact parameters required.",
|
|
652
|
+
inputSchema: {
|
|
653
|
+
type: "object",
|
|
654
|
+
properties: {
|
|
655
|
+
names: {
|
|
656
|
+
type: "array",
|
|
657
|
+
items: { type: "string" },
|
|
658
|
+
description: 'Tool names to get schemas for (e.g. ["gmail_send_email", "github_list_repos"])'
|
|
659
|
+
}
|
|
660
|
+
},
|
|
661
|
+
required: ["names"]
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
{
|
|
665
|
+
name: "kojee_call_tool",
|
|
666
|
+
description: "Call a Kojee tool by name with the specified arguments. Use the connector tools (e.g. kojee_gmail) to discover tools, then kojee_get_tool_schema to get parameters, then this to execute.",
|
|
667
|
+
inputSchema: {
|
|
668
|
+
type: "object",
|
|
669
|
+
properties: {
|
|
670
|
+
name: {
|
|
671
|
+
type: "string",
|
|
672
|
+
description: 'The tool name (e.g. "gmail_send_email")'
|
|
673
|
+
},
|
|
674
|
+
arguments: {
|
|
675
|
+
type: "object",
|
|
676
|
+
description: "The tool arguments matching the tool's input schema",
|
|
677
|
+
additionalProperties: true
|
|
678
|
+
}
|
|
679
|
+
},
|
|
680
|
+
required: ["name"]
|
|
681
|
+
}
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
name: "kojee_check_approval",
|
|
685
|
+
description: "Check the status of a pending approval request. Use this after a tool call returns 'require_approval' to poll whether the user has approved or denied.",
|
|
686
|
+
inputSchema: {
|
|
687
|
+
type: "object",
|
|
688
|
+
properties: {
|
|
689
|
+
approval_id: {
|
|
690
|
+
type: "string",
|
|
691
|
+
description: "The approval ID returned when a tool call requires approval"
|
|
692
|
+
}
|
|
693
|
+
},
|
|
694
|
+
required: ["approval_id"]
|
|
695
|
+
}
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
name: "kojee_revoke_request",
|
|
699
|
+
description: "Revoke/cancel a pending approval request you no longer need.",
|
|
700
|
+
inputSchema: {
|
|
701
|
+
type: "object",
|
|
702
|
+
properties: {
|
|
703
|
+
approval_id: {
|
|
704
|
+
type: "string",
|
|
705
|
+
description: "The approval ID to revoke"
|
|
706
|
+
},
|
|
707
|
+
reason: {
|
|
708
|
+
type: "string",
|
|
709
|
+
description: "Optional reason for revoking"
|
|
710
|
+
}
|
|
711
|
+
},
|
|
712
|
+
required: ["approval_id"]
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
];
|
|
660
716
|
function createMcpServer(registry) {
|
|
661
717
|
const server = new Server(
|
|
662
718
|
{
|
|
663
719
|
name: "kojee-mcp",
|
|
664
|
-
version: "0.1.
|
|
720
|
+
version: "0.1.1"
|
|
665
721
|
},
|
|
666
722
|
{
|
|
667
723
|
capabilities: {
|
|
@@ -670,21 +726,70 @@ function createMcpServer(registry) {
|
|
|
670
726
|
}
|
|
671
727
|
);
|
|
672
728
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
673
|
-
const
|
|
674
|
-
|
|
675
|
-
description: t.description,
|
|
676
|
-
inputSchema: t.inputSchema
|
|
677
|
-
}));
|
|
678
|
-
return { tools };
|
|
729
|
+
const connectorTools = registry.getConnectorTools();
|
|
730
|
+
return { tools: [...connectorTools, ...UTILITY_TOOLS] };
|
|
679
731
|
});
|
|
680
732
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
681
733
|
const { name, arguments: args } = request.params;
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
734
|
+
if (name.startsWith(CONNECTOR_TOOL_PREFIX) && !UTILITY_TOOLS.some((t) => t.name === name)) {
|
|
735
|
+
const connectorId = name.substring(CONNECTOR_TOOL_PREFIX.length);
|
|
736
|
+
const toolList = registry.getConnectorToolList(connectorId);
|
|
737
|
+
return {
|
|
738
|
+
content: [{ type: "text", text: toolList }],
|
|
739
|
+
isError: false
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
switch (name) {
|
|
743
|
+
case "kojee_get_tool_schema": {
|
|
744
|
+
const names = args?.names ?? [];
|
|
745
|
+
if (names.length === 0) {
|
|
746
|
+
return {
|
|
747
|
+
content: [{ type: "text", text: "Provide tool names in the 'names' array." }],
|
|
748
|
+
isError: true
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
const schemas = await registry.getToolSchemas(names);
|
|
752
|
+
return {
|
|
753
|
+
content: [{ type: "text", text: JSON.stringify(schemas, null, 2) }],
|
|
754
|
+
isError: false
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
case "kojee_call_tool": {
|
|
758
|
+
const toolName = args?.name;
|
|
759
|
+
if (!toolName) {
|
|
760
|
+
return {
|
|
761
|
+
content: [{ type: "text", text: "Provide the tool name in the 'name' field." }],
|
|
762
|
+
isError: true
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
const toolArgs = args?.arguments ?? {};
|
|
766
|
+
const rawResult = await registry.callTool(toolName, toolArgs);
|
|
767
|
+
const result = translateToolCallResult(rawResult);
|
|
768
|
+
return {
|
|
769
|
+
content: result.content,
|
|
770
|
+
isError: result.isError
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
case "kojee_check_approval":
|
|
774
|
+
case "kojee_revoke_request": {
|
|
775
|
+
const rawResult = await registry.callTool(name, args ?? {});
|
|
776
|
+
const result = translateToolCallResult(rawResult);
|
|
777
|
+
return {
|
|
778
|
+
content: result.content,
|
|
779
|
+
isError: result.isError
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
default:
|
|
783
|
+
return {
|
|
784
|
+
content: [
|
|
785
|
+
{
|
|
786
|
+
type: "text",
|
|
787
|
+
text: `Unknown tool '${name}'. Use one of the connector tools or utility tools.`
|
|
788
|
+
}
|
|
789
|
+
],
|
|
790
|
+
isError: true
|
|
791
|
+
};
|
|
792
|
+
}
|
|
688
793
|
});
|
|
689
794
|
return server;
|
|
690
795
|
}
|
|
@@ -716,9 +821,8 @@ async function startProxy(config) {
|
|
|
716
821
|
);
|
|
717
822
|
const registry = new ToolRegistry(gateway);
|
|
718
823
|
await registry.discoverTools();
|
|
719
|
-
const toolCount = registry.getTools().length;
|
|
720
824
|
console.error(
|
|
721
|
-
`[kojee-mcp] Ready \u2014 ${toolCount} tools
|
|
825
|
+
`[kojee-mcp] Ready \u2014 ${registry.toolCount} tools available from ${config.url}`
|
|
722
826
|
);
|
|
723
827
|
const server = createMcpServer(registry);
|
|
724
828
|
await startMcpServer(server);
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kojee-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Local MCP proxy for Kojee — handles DPoP auth, tool discovery, and governance transparently",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
|
-
"bin": {
|
|
7
|
+
"bin": {
|
|
8
|
+
"kojee-mcp": "dist/cli.js"
|
|
9
|
+
},
|
|
8
10
|
"scripts": {
|
|
9
11
|
"build": "tsup src/cli.ts src/index.ts --format esm --dts --clean",
|
|
10
12
|
"dev": "tsup src/cli.ts --format esm --watch",
|
|
11
13
|
"typecheck": "tsc --noEmit"
|
|
12
14
|
},
|
|
13
|
-
"files": [
|
|
14
|
-
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"mcp",
|
|
20
|
+
"kojee",
|
|
21
|
+
"ai-governance",
|
|
22
|
+
"agent-tools",
|
|
23
|
+
"dpop"
|
|
24
|
+
],
|
|
15
25
|
"license": "MIT",
|
|
16
26
|
"dependencies": {
|
|
17
27
|
"@modelcontextprotocol/sdk": "latest",
|