kojee-mcp 0.1.0 → 0.1.2

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.
@@ -517,137 +517,124 @@ function sleep(ms) {
517
517
  }
518
518
 
519
519
  // src/tool-registry.ts
520
- var KOJEE_PREFIX = "kojee_";
521
- var isBuiltinTool = (name) => name.startsWith(KOJEE_PREFIX);
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
- /** Map from agent-facing name (prefixed) to full tool definition */
528
- tools = /* @__PURE__ */ new Map();
529
- /** Map from agent-facing name to gateway name */
530
- nameMap = /* @__PURE__ */ new Map();
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
- * Discover tools from the gateway:
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
- if (isBuiltinTool(tool.name)) {
551
- builtinTools.push(tool);
552
- } else {
553
- connectorToolNames.push(tool.name);
554
- }
555
- }
556
- if (builtinTools.length > 0) {
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(`[tools] Registered ${this.tools.size} tools`);
562
+ console.error(
563
+ `[tools] Discovered ${this.allToolNames.size} tools across ${this.connectors.size} connectors`
564
+ );
604
565
  }
605
566
  /**
606
- * Register a single tool, applying the kojee_ prefix if needed.
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
- registerTool(tool) {
609
- const gatewayName = tool.name;
610
- const agentName = gatewayName.startsWith(KOJEE_PREFIX) ? gatewayName : `${KOJEE_PREFIX}${gatewayName}`;
611
- this.nameMap.set(agentName, gatewayName);
612
- this.tools.set(agentName, {
613
- ...tool,
614
- name: agentName
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: 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 all registered tools as MCP tool definitions for the agent.
584
+ * Get the detailed tool list for a specific connector.
619
585
  */
620
- getTools() {
621
- return Array.from(this.tools.values());
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
- * Resolve an agent-facing tool name to its gateway name.
625
- * Returns null if the tool is not registered.
599
+ * Get full schemas for specific tools via tools/get_schema.
626
600
  */
627
- resolveGatewayName(agentName) {
628
- return this.nameMap.get(agentName) ?? null;
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, handling name mapping.
610
+ * Call a tool through the gateway.
632
611
  */
633
- async callTool(agentName, args) {
634
- const gatewayName = this.resolveGatewayName(agentName);
635
- if (!gatewayName) {
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 '${agentName}' not found. It may have been removed or your token lacks access.`
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: gatewayName,
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,85 @@ import {
657
644
  ListToolsRequestSchema,
658
645
  CallToolRequestSchema
659
646
  } 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
+ ];
660
721
  function createMcpServer(registry) {
661
722
  const server = new Server(
662
723
  {
663
724
  name: "kojee-mcp",
664
- version: "0.1.0"
725
+ version: "0.1.1"
665
726
  },
666
727
  {
667
728
  capabilities: {
@@ -670,21 +731,69 @@ function createMcpServer(registry) {
670
731
  }
671
732
  );
672
733
  server.setRequestHandler(ListToolsRequestSchema, async () => {
673
- const tools = registry.getTools().map((t) => ({
674
- name: t.name,
675
- description: t.description,
676
- inputSchema: t.inputSchema
677
- }));
678
- return { tools };
734
+ const connectorTools = registry.getConnectorTools();
735
+ return { tools: [...connectorTools, ...UTILITY_TOOLS] };
679
736
  });
680
737
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
681
738
  const { name, arguments: args } = request.params;
682
- const rawResult = await registry.callTool(name, args ?? {});
683
- const result = translateToolCallResult(rawResult);
684
- return {
685
- content: result.content,
686
- isError: result.isError
687
- };
739
+ if (!UTILITY_TOOL_NAMES.has(name)) {
740
+ const toolList = registry.getConnectorToolList(name);
741
+ return {
742
+ content: [{ type: "text", text: toolList }],
743
+ isError: false
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
+ }
688
797
  });
689
798
  return server;
690
799
  }
@@ -716,9 +825,8 @@ async function startProxy(config) {
716
825
  );
717
826
  const registry = new ToolRegistry(gateway);
718
827
  await registry.discoverTools();
719
- const toolCount = registry.getTools().length;
720
828
  console.error(
721
- `[kojee-mcp] Ready \u2014 ${toolCount} tools proxied from ${config.url}`
829
+ `[kojee-mcp] Ready \u2014 ${registry.toolCount} tools available from ${config.url}`
722
830
  );
723
831
  const server = createMcpServer(registry);
724
832
  await startMcpServer(server);
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startProxy
4
- } from "./chunk-UDF4BJS5.js";
4
+ } from "./chunk-WIXI3EVR.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { Command } from "commander";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  startProxy
3
- } from "./chunk-UDF4BJS5.js";
3
+ } from "./chunk-WIXI3EVR.js";
4
4
  export {
5
5
  startProxy
6
6
  };
package/package.json CHANGED
@@ -1,17 +1,27 @@
1
1
  {
2
2
  "name": "kojee-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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": { "kojee-mcp": "dist/cli.js" },
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": ["dist"],
14
- "keywords": ["mcp", "kojee", "ai-governance", "agent-tools", "dpop"],
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",