kojee-mcp 0.1.2 → 0.2.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 +1 -1
- package/dist/{chunk-WIXI3EVR.js → chunk-O5UYOIQX.js} +33 -214
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ kojee-mcp is a local MCP proxy that lets any MCP-capable agent use Kojee-managed
|
|
|
6
6
|
|
|
7
7
|
1. **Get a gateway token** from the [Kojee dashboard](https://kojee.ai).
|
|
8
8
|
2. **Add to your MCP config** (see examples below).
|
|
9
|
-
3. **Tools appear automatically** --
|
|
9
|
+
3. **Tools appear automatically** -- all Kojee tools your token has access to are exposed directly (e.g. `gmail_send_email`, `github_list_repos`, `calendar_create_event`). Agents call them like any native MCP tool — no discovery step, no wrapper, no indirection.
|
|
10
10
|
|
|
11
11
|
## MCP Config Examples
|
|
12
12
|
|
|
@@ -517,106 +517,51 @@ function sleep(ms) {
|
|
|
517
517
|
}
|
|
518
518
|
|
|
519
519
|
// src/tool-registry.ts
|
|
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
|
-
}
|
|
531
520
|
var ToolRegistry = class {
|
|
532
521
|
constructor(gateway) {
|
|
533
522
|
this.gateway = gateway;
|
|
534
523
|
}
|
|
535
524
|
gateway;
|
|
536
|
-
/**
|
|
537
|
-
|
|
538
|
-
/** All tool names (flat) for validation */
|
|
539
|
-
allToolNames = /* @__PURE__ */ new Set();
|
|
525
|
+
/** Flat map: tool name → full tool definition */
|
|
526
|
+
tools = /* @__PURE__ */ new Map();
|
|
540
527
|
/**
|
|
541
|
-
* Fetch
|
|
528
|
+
* Fetch all tools with full schemas from the gateway in a single RPC call.
|
|
542
529
|
*/
|
|
543
530
|
async discoverTools() {
|
|
544
|
-
console.error("[tools] Fetching
|
|
545
|
-
const
|
|
546
|
-
|
|
531
|
+
console.error("[tools] Fetching tools with full schemas from gateway...");
|
|
532
|
+
const result = await this.gateway.sendRpc("tools/list", {
|
|
533
|
+
include_schema: true
|
|
534
|
+
});
|
|
535
|
+
const toolList = result?.tools;
|
|
547
536
|
if (!toolList || !Array.isArray(toolList)) {
|
|
548
537
|
console.error("[tools] No tools returned from gateway");
|
|
549
538
|
return;
|
|
550
539
|
}
|
|
551
540
|
for (const tool of toolList) {
|
|
552
|
-
this.
|
|
553
|
-
|
|
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);
|
|
541
|
+
if (this.tools.has(tool.name)) {
|
|
542
|
+
console.error(`[tools] Warning: duplicate tool name "${tool.name}" \u2014 overwriting`);
|
|
559
543
|
}
|
|
560
|
-
|
|
561
|
-
}
|
|
562
|
-
console.error(
|
|
563
|
-
`[tools] Discovered ${this.allToolNames.size} tools across ${this.connectors.size} connectors`
|
|
564
|
-
);
|
|
565
|
-
}
|
|
566
|
-
/**
|
|
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.
|
|
570
|
-
*/
|
|
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: 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;
|
|
582
|
-
}
|
|
583
|
-
/**
|
|
584
|
-
* Get the detailed tool list for a specific connector.
|
|
585
|
-
*/
|
|
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(", ")}`;
|
|
544
|
+
this.tools.set(tool.name, tool);
|
|
590
545
|
}
|
|
591
|
-
|
|
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.`;
|
|
546
|
+
console.error(`[tools] Registered ${this.tools.size} tools from gateway`);
|
|
597
547
|
}
|
|
598
548
|
/**
|
|
599
|
-
*
|
|
549
|
+
* Return all registered tools for the MCP ListTools response.
|
|
600
550
|
*/
|
|
601
|
-
|
|
602
|
-
|
|
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 ?? [];
|
|
551
|
+
getAllTools() {
|
|
552
|
+
return Array.from(this.tools.values());
|
|
608
553
|
}
|
|
609
554
|
/**
|
|
610
555
|
* Call a tool through the gateway.
|
|
611
556
|
*/
|
|
612
557
|
async callTool(name, args) {
|
|
613
|
-
if (!this.
|
|
614
|
-
const available = Array.from(this.
|
|
558
|
+
if (!this.tools.has(name)) {
|
|
559
|
+
const available = Array.from(this.tools.keys()).slice(0, 10).join(", ");
|
|
615
560
|
return {
|
|
616
561
|
content: [
|
|
617
562
|
{
|
|
618
563
|
type: "text",
|
|
619
|
-
text: `Tool '${name}' not found.
|
|
564
|
+
text: `Tool '${name}' not found. Some available tools: ${available}${this.tools.size > 10 ? ", ..." : ""}`
|
|
620
565
|
}
|
|
621
566
|
],
|
|
622
567
|
isError: true
|
|
@@ -627,13 +572,9 @@ Use kojee_get_tool_schema to get the full input schema, then kojee_call_tool to
|
|
|
627
572
|
arguments: args
|
|
628
573
|
});
|
|
629
574
|
}
|
|
630
|
-
/**
|
|
631
|
-
get connectorIds() {
|
|
632
|
-
return Array.from(this.connectors.keys());
|
|
633
|
-
}
|
|
634
|
-
/** Total number of discovered tools. */
|
|
575
|
+
/** Total number of registered tools. */
|
|
635
576
|
get toolCount() {
|
|
636
|
-
return this.
|
|
577
|
+
return this.tools.size;
|
|
637
578
|
}
|
|
638
579
|
};
|
|
639
580
|
|
|
@@ -644,85 +585,11 @@ import {
|
|
|
644
585
|
ListToolsRequestSchema,
|
|
645
586
|
CallToolRequestSchema
|
|
646
587
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
647
|
-
var UTILITY_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
648
|
-
"get_tool_schema",
|
|
649
|
-
"call_tool",
|
|
650
|
-
"check_approval",
|
|
651
|
-
"revoke_request"
|
|
652
|
-
]);
|
|
653
|
-
var UTILITY_TOOLS = [
|
|
654
|
-
{
|
|
655
|
-
name: "get_tool_schema",
|
|
656
|
-
description: "Get the full input schema for one or more Kojee tools. Call this before call_tool to know the exact parameters required.",
|
|
657
|
-
inputSchema: {
|
|
658
|
-
type: "object",
|
|
659
|
-
properties: {
|
|
660
|
-
names: {
|
|
661
|
-
type: "array",
|
|
662
|
-
items: { type: "string" },
|
|
663
|
-
description: 'Tool names to get schemas for (e.g. ["gmail_send_email", "github_list_repos"])'
|
|
664
|
-
}
|
|
665
|
-
},
|
|
666
|
-
required: ["names"]
|
|
667
|
-
}
|
|
668
|
-
},
|
|
669
|
-
{
|
|
670
|
-
name: "call_tool",
|
|
671
|
-
description: "Call a Kojee tool by name with the specified arguments. Use the connector tools (e.g. kojee_gmail) to discover tools, then get_tool_schema to get parameters, then this to execute.",
|
|
672
|
-
inputSchema: {
|
|
673
|
-
type: "object",
|
|
674
|
-
properties: {
|
|
675
|
-
name: {
|
|
676
|
-
type: "string",
|
|
677
|
-
description: 'The tool name (e.g. "gmail_send_email")'
|
|
678
|
-
},
|
|
679
|
-
arguments: {
|
|
680
|
-
type: "object",
|
|
681
|
-
description: "The tool arguments matching the tool's input schema",
|
|
682
|
-
additionalProperties: true
|
|
683
|
-
}
|
|
684
|
-
},
|
|
685
|
-
required: ["name"]
|
|
686
|
-
}
|
|
687
|
-
},
|
|
688
|
-
{
|
|
689
|
-
name: "check_approval",
|
|
690
|
-
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.",
|
|
691
|
-
inputSchema: {
|
|
692
|
-
type: "object",
|
|
693
|
-
properties: {
|
|
694
|
-
approval_id: {
|
|
695
|
-
type: "string",
|
|
696
|
-
description: "The approval ID returned when a tool call requires approval"
|
|
697
|
-
}
|
|
698
|
-
},
|
|
699
|
-
required: ["approval_id"]
|
|
700
|
-
}
|
|
701
|
-
},
|
|
702
|
-
{
|
|
703
|
-
name: "revoke_request",
|
|
704
|
-
description: "Revoke/cancel a pending approval request you no longer need.",
|
|
705
|
-
inputSchema: {
|
|
706
|
-
type: "object",
|
|
707
|
-
properties: {
|
|
708
|
-
approval_id: {
|
|
709
|
-
type: "string",
|
|
710
|
-
description: "The approval ID to revoke"
|
|
711
|
-
},
|
|
712
|
-
reason: {
|
|
713
|
-
type: "string",
|
|
714
|
-
description: "Optional reason for revoking"
|
|
715
|
-
}
|
|
716
|
-
},
|
|
717
|
-
required: ["approval_id"]
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
];
|
|
721
588
|
function createMcpServer(registry) {
|
|
722
589
|
const server = new Server(
|
|
723
590
|
{
|
|
724
591
|
name: "kojee-mcp",
|
|
725
|
-
version: "0.
|
|
592
|
+
version: "0.2.0"
|
|
726
593
|
},
|
|
727
594
|
{
|
|
728
595
|
capabilities: {
|
|
@@ -731,69 +598,21 @@ function createMcpServer(registry) {
|
|
|
731
598
|
}
|
|
732
599
|
);
|
|
733
600
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
734
|
-
const
|
|
735
|
-
|
|
601
|
+
const tools = registry.getAllTools().map((t) => ({
|
|
602
|
+
name: t.name,
|
|
603
|
+
description: t.description,
|
|
604
|
+
inputSchema: t.inputSchema
|
|
605
|
+
}));
|
|
606
|
+
return { tools };
|
|
736
607
|
});
|
|
737
608
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
738
609
|
const { name, arguments: args } = request.params;
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
}
|
|
746
|
-
switch (name) {
|
|
747
|
-
case "get_tool_schema": {
|
|
748
|
-
const names = args?.names ?? [];
|
|
749
|
-
if (names.length === 0) {
|
|
750
|
-
return {
|
|
751
|
-
content: [{ type: "text", text: "Provide tool names in the 'names' array." }],
|
|
752
|
-
isError: true
|
|
753
|
-
};
|
|
754
|
-
}
|
|
755
|
-
const schemas = await registry.getToolSchemas(names);
|
|
756
|
-
return {
|
|
757
|
-
content: [{ type: "text", text: JSON.stringify(schemas, null, 2) }],
|
|
758
|
-
isError: false
|
|
759
|
-
};
|
|
760
|
-
}
|
|
761
|
-
case "call_tool": {
|
|
762
|
-
const toolName = args?.name;
|
|
763
|
-
if (!toolName) {
|
|
764
|
-
return {
|
|
765
|
-
content: [{ type: "text", text: "Provide the tool name in the 'name' field." }],
|
|
766
|
-
isError: true
|
|
767
|
-
};
|
|
768
|
-
}
|
|
769
|
-
const toolArgs = args?.arguments ?? {};
|
|
770
|
-
const rawResult = await registry.callTool(toolName, toolArgs);
|
|
771
|
-
const result = translateToolCallResult(rawResult);
|
|
772
|
-
return {
|
|
773
|
-
content: result.content,
|
|
774
|
-
isError: result.isError
|
|
775
|
-
};
|
|
776
|
-
}
|
|
777
|
-
case "check_approval":
|
|
778
|
-
case "revoke_request": {
|
|
779
|
-
const rawResult = await registry.callTool(name, args ?? {});
|
|
780
|
-
const result = translateToolCallResult(rawResult);
|
|
781
|
-
return {
|
|
782
|
-
content: result.content,
|
|
783
|
-
isError: result.isError
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
|
-
default:
|
|
787
|
-
return {
|
|
788
|
-
content: [
|
|
789
|
-
{
|
|
790
|
-
type: "text",
|
|
791
|
-
text: `Unknown tool '${name}'. Use one of the connector tools or utility tools.`
|
|
792
|
-
}
|
|
793
|
-
],
|
|
794
|
-
isError: true
|
|
795
|
-
};
|
|
796
|
-
}
|
|
610
|
+
const rawResult = await registry.callTool(name, args ?? {});
|
|
611
|
+
const result = translateToolCallResult(rawResult);
|
|
612
|
+
return {
|
|
613
|
+
content: result.content,
|
|
614
|
+
isError: result.isError
|
|
615
|
+
};
|
|
797
616
|
});
|
|
798
617
|
return server;
|
|
799
618
|
}
|
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED