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.
@@ -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: `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 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,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.0"
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 tools = registry.getTools().map((t) => ({
674
- name: t.name,
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
- const rawResult = await registry.callTool(name, args ?? {});
683
- const result = translateToolCallResult(rawResult);
684
- return {
685
- content: result.content,
686
- isError: result.isError
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 proxied from ${config.url}`
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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  startProxy
4
- } from "./chunk-UDF4BJS5.js";
4
+ } from "./chunk-TJNNT7XM.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-TJNNT7XM.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.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": { "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",