@olane/o-mcp 0.6.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.
Files changed (38) hide show
  1. package/README.md +86 -0
  2. package/dist/src/index.d.ts +3 -0
  3. package/dist/src/index.d.ts.map +1 -0
  4. package/dist/src/index.js +2 -0
  5. package/dist/src/mcp-bridge.tool.d.ts +12 -0
  6. package/dist/src/mcp-bridge.tool.d.ts.map +1 -0
  7. package/dist/src/mcp-bridge.tool.js +109 -0
  8. package/dist/src/mcp.tool.d.ts +15 -0
  9. package/dist/src/mcp.tool.d.ts.map +1 -0
  10. package/dist/src/mcp.tool.js +89 -0
  11. package/dist/src/methods/mcp-bridge.methods.d.ts +5 -0
  12. package/dist/src/methods/mcp-bridge.methods.d.ts.map +1 -0
  13. package/dist/src/methods/mcp-bridge.methods.js +65 -0
  14. package/dist/src/o-client.mcp.d.ts +15 -0
  15. package/dist/src/o-client.mcp.d.ts.map +1 -0
  16. package/dist/src/o-client.mcp.js +15 -0
  17. package/dist/src/o-server.mcp.d.ts +13 -0
  18. package/dist/src/o-server.mcp.d.ts.map +1 -0
  19. package/dist/src/o-server.mcp.js +23 -0
  20. package/dist/src/o-transport.mcp.d.ts +17 -0
  21. package/dist/src/o-transport.mcp.d.ts.map +1 -0
  22. package/dist/src/o-transport.mcp.js +55 -0
  23. package/dist/test/benchmark.spec.d.ts +2 -0
  24. package/dist/test/benchmark.spec.d.ts.map +1 -0
  25. package/dist/test/benchmark.spec.js +48 -0
  26. package/dist/test/benchmarks/github/github.test-cases.d.ts +3 -0
  27. package/dist/test/benchmarks/github/github.test-cases.d.ts.map +1 -0
  28. package/dist/test/benchmarks/github/github.test-cases.js +10 -0
  29. package/dist/test/benchmarks/interfaces/test-case.interface.d.ts +10 -0
  30. package/dist/test/benchmarks/interfaces/test-case.interface.d.ts.map +1 -0
  31. package/dist/test/benchmarks/interfaces/test-case.interface.js +1 -0
  32. package/dist/test/utils/mcp-repo.d.ts +2 -0
  33. package/dist/test/utils/mcp-repo.d.ts.map +1 -0
  34. package/dist/test/utils/mcp-repo.js +5 -0
  35. package/dist/test/utils/models.d.ts +9 -0
  36. package/dist/test/utils/models.d.ts.map +1 -0
  37. package/dist/test/utils/models.js +8 -0
  38. package/package.json +74 -0
package/README.md ADDED
@@ -0,0 +1,86 @@
1
+ TLDR; we created a forked MCP version that is faster, better, and cheaper. [Link to get started]
2
+
3
+ ## What is MCP Missing?
4
+
5
+ ### **Today / Problem Description**
6
+
7
+ MCP servers are built to enable LLM / AI systems to synthesize workflows from complex tasks. This means MCPs will work great if…
8
+
9
+ 1. You have built your MCP well (example: *as an intention-based tool, not as an API wrapper)*
10
+ 1. *You actively maintain* documentation to support *how* to use your services
11
+ 2. LLM / AI understands how to synthesize plans around small workflows using the tools provided
12
+ 2. You pay for intelligent models that can reason / do chain of thought processing.
13
+
14
+ Every LLM / AI system will need to rerun this, every time. Today it has no working memory on the workflows/plans it runs.
15
+
16
+ We asked ourselves…”why are these plans and workflows being thrown out?”
17
+
18
+ ### **Olane + MCP = oMCP**
19
+
20
+ We have forked the MCP client & server to capture and re-use these workflows, reducing intelligence requirements and improving MCP completion by X%. [Link to the repo]
21
+
22
+ ## How did we do this?
23
+
24
+ We centered our focus on these problems:
25
+
26
+ 1. How can we enable smaller models to succeed just like bigger ones?
27
+ 2. How can we reduce waste / reduce token usage?
28
+ 3. How can we make AI - MCP usage more deterministic?
29
+ 4. How can we improve the speed of MCP usage?
30
+
31
+ Like teaching a small child, we learned that by simply following the KISS model (KISS → “keep it simple stupid”), we achieved all of this and more.
32
+
33
+ > Smaller AI models need less noise and more clear instruction to succeed. In other words, “spell it out for them”
34
+ >
35
+
36
+ <aside>
37
+ 💡
38
+
39
+ *Engaging / thoughtful hook? Brendon scratchpad*
40
+
41
+ How do you get the *right* context from an MCP server to complete your task?
42
+
43
+ - Do you just throw everything at it? → No, this is wasteful
44
+ - Do you try to condense the knowledge to cost optimize? → Maybe…but how without data loss
45
+ - Do you try to organize MCP usage and learn from similar use-cases? Let’s try it and see what happens…
46
+ </aside>
47
+
48
+ ![normal-mcp.png](./docs/assets/normal-mcp.png)
49
+
50
+ ![o-mcp-flow.png](./docs/assets/o-mcp-flow.png)
51
+
52
+ ### Breaking it down further…
53
+
54
+ We combine large model successes + failures + a little search to help give small models a helping hand in achieving their dreams.
55
+
56
+ <aside>
57
+ 💡
58
+
59
+ We learn from past successes & failures to create few shot RL guidelines on how to best utilize the MCP server.
60
+
61
+ </aside>
62
+
63
+ **Example**:
64
+
65
+ ```
66
+ “Get my latest pull requests”
67
+ Results in the following steps:
68
+
69
+ 1. Client connects to MCP server with an “intent” + “model”
70
+ 2. The MCP server searches for past success, failure and relevant tool methods
71
+ 3. Client receives the package and creates new "workflow" tool uses
72
+ 4. Execute!
73
+ ```
74
+
75
+ ### So how does this meet our goals?
76
+
77
+ 1. Smaller model support → more relevant / clear context is now achieved
78
+ 2. Reduce token usage → avoid sending irrelevant context when possible / refine tool offerings & also reduce model size requirements
79
+ 3. More deterministic → by learning from past failures & successes, we know how to stay within the bounds of success with clear guardrails
80
+ 4. Speed improvement → less tokens to process = more speed
81
+
82
+ ### Examples
83
+
84
+ 1. Github example → what models can we test / prove to how it works?
85
+ 2. Figma example → same as above ^^
86
+ 3. Slack / more complex examples → same as above ^
@@ -0,0 +1,3 @@
1
+ export * from './mcp-bridge.tool.js';
2
+ export * from './mcp.tool.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './mcp-bridge.tool.js';
2
+ export * from './mcp.tool.js';
@@ -0,0 +1,12 @@
1
+ import { oToolConfig, oVirtualTool, ToolResult } from '@olane/o-tool';
2
+ import { oRequest } from '@olane/o-core';
3
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
4
+ import { McpTool } from './mcp.tool.js';
5
+ export declare class McpBridgeTool extends oVirtualTool {
6
+ constructor(config: oToolConfig);
7
+ _tool_validate_url(request: oRequest): Promise<ToolResult>;
8
+ _tool_add_remote_server(request: oRequest): Promise<ToolResult>;
9
+ _tool_add_local_server(request: oRequest): Promise<ToolResult>;
10
+ createMcpTool(mcpClient: Client, url: string, name?: string): Promise<McpTool>;
11
+ }
12
+ //# sourceMappingURL=mcp-bridge.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-bridge.tool.d.ts","sourceRoot":"","sources":["../../src/mcp-bridge.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAY,QAAQ,EAAc,MAAM,eAAe,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAEnE,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAIxC,qBAAa,aAAc,SAAQ,YAAY;gBACjC,MAAM,EAAE,WAAW;IASzB,kBAAkB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAsB1D,uBAAuB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IAuC/D,sBAAsB,CAAC,OAAO,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC;IA+B9D,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC;CAuBpB"}
@@ -0,0 +1,109 @@
1
+ import { oVirtualTool } from '@olane/o-tool';
2
+ import { oAddress } from '@olane/o-core';
3
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
4
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
5
+ import { McpTool } from './mcp.tool.js';
6
+ import { MCP_BRIDGE_METHODS } from './methods/mcp-bridge.methods.js';
7
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
8
+ export class McpBridgeTool extends oVirtualTool {
9
+ constructor(config) {
10
+ super({
11
+ ...config,
12
+ address: new oAddress('o://mcp'),
13
+ description: 'Tool to help add MCP servers to the network',
14
+ methods: MCP_BRIDGE_METHODS,
15
+ });
16
+ }
17
+ async _tool_validate_url(request) {
18
+ const params = request.params;
19
+ const { mcpServerUrl } = params;
20
+ // check the URL contents to see if it is a valid MCP server or a link describing one
21
+ const response = await this.use(new oAddress('o://perplexity'), {
22
+ method: 'completion',
23
+ params: {
24
+ model: 'sonar',
25
+ messages: [
26
+ {
27
+ role: 'user',
28
+ content: `Is this url an MCP server: ${mcpServerUrl}? Be concise in your answer.`,
29
+ },
30
+ ],
31
+ },
32
+ });
33
+ return {
34
+ result: response.result.data.message,
35
+ };
36
+ }
37
+ async _tool_add_remote_server(request) {
38
+ const params = request.params;
39
+ // params have already been validated
40
+ const { mcpServerUrl, headers } = params;
41
+ try {
42
+ this.logger.debug('Adding MCP server: ' + mcpServerUrl);
43
+ const transport = new StreamableHTTPClientTransport(new URL(mcpServerUrl), {
44
+ requestInit: {
45
+ headers: headers,
46
+ },
47
+ });
48
+ const mcpClient = new Client({
49
+ name: 'o-node:mcp:' + this.peerId.toString(),
50
+ version: '1.0.0',
51
+ headers: headers,
52
+ });
53
+ await mcpClient.connect(transport);
54
+ await this.createMcpTool(mcpClient, mcpServerUrl);
55
+ return {
56
+ message: 'Successfully added MCP server with ' +
57
+ this.childNodes.length +
58
+ ' tools',
59
+ };
60
+ }
61
+ catch (e) {
62
+ throw new Error('Error when trying to add MCP server (' +
63
+ mcpServerUrl +
64
+ ') to the network: ' +
65
+ e?.message);
66
+ }
67
+ }
68
+ async _tool_add_local_server(request) {
69
+ const params = request.params;
70
+ this.logger.debug('Adding local MCP server: ', params);
71
+ // params have already been validated
72
+ const { command, args, name } = params;
73
+ // this.logger.debug('Adding local MCP server: ' + mcpServerUrl);
74
+ const transport = new StdioClientTransport({
75
+ command: command,
76
+ args: args,
77
+ });
78
+ const mcpClient = new Client({
79
+ name: 'o-node:mcp:' + this.peerId.toString(),
80
+ version: '1.0.0',
81
+ });
82
+ await mcpClient.connect(transport);
83
+ await this.createMcpTool(mcpClient, args.join(' '), name);
84
+ return {
85
+ _save: true,
86
+ message: 'Successfully added local MCP server',
87
+ };
88
+ }
89
+ async createMcpTool(mcpClient, url, name) {
90
+ this.logger.debug('Creating MCP tool: ', name, url);
91
+ const mcpTool = new McpTool({
92
+ name: name || 'mcp-' + Date.now(),
93
+ description: 'MCP server for ' + url,
94
+ address: new oAddress(`o://${name || `mcp-${Date.now()}`}`),
95
+ mcpClient: mcpClient,
96
+ dependencies: [],
97
+ leader: this.config.leader,
98
+ parent: this.address,
99
+ });
100
+ this.addChildNode(mcpTool);
101
+ await this.startChildren();
102
+ await mcpTool.setupTools();
103
+ await this.use(new oAddress(mcpTool.address.toString()), {
104
+ method: 'index_network',
105
+ params: {},
106
+ });
107
+ return mcpTool;
108
+ }
109
+ }
@@ -0,0 +1,15 @@
1
+ import { oToolConfig, oVirtualTool } from '@olane/o-tool';
2
+ import { oAddress } from '@olane/o-core';
3
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
4
+ export declare class McpTool extends oVirtualTool {
5
+ private mcpClient;
6
+ constructor(config: oToolConfig & {
7
+ address: oAddress;
8
+ mcpClient: Client;
9
+ });
10
+ setupTools(): Promise<void>;
11
+ myTools(): Promise<string[]>;
12
+ index(): Promise<any>;
13
+ whoami(): Promise<any>;
14
+ }
15
+ //# sourceMappingURL=mcp.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.tool.d.ts","sourceRoot":"","sources":["../../src/mcp.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAyC,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAGnE,qBAAa,OAAQ,SAAQ,YAAY;IACvC,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,WAAW,GAAG;QAAE,OAAO,EAAE,QAAQ,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAYpE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC3B,OAAO;IAQP,KAAK;IA2BL,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC;CAmB7B"}
@@ -0,0 +1,89 @@
1
+ import { oVirtualTool } from '@olane/o-tool';
2
+ import { oAddress, oToolError, oToolErrorCodes } from '@olane/o-core';
3
+ import { v4 as uuidv4 } from 'uuid';
4
+ export class McpTool extends oVirtualTool {
5
+ constructor(config) {
6
+ super({
7
+ ...config,
8
+ address: config.address,
9
+ description: config.description ||
10
+ 'Tool for wrapping MCP servers to be used as tools in the network',
11
+ });
12
+ this.mcpClient = config.mcpClient;
13
+ }
14
+ // _tool_ functions are dynamically added to the tool based on the MCP server's methods
15
+ async setupTools() {
16
+ this.logger.debug('Setting up MCP tools');
17
+ const tools = await this.mcpClient.listTools();
18
+ this.logger.debug('MCP tools: ', tools);
19
+ tools.tools.forEach((tool) => {
20
+ this.logger.debug('Setting up MCP server tool: ' + tool.name);
21
+ this.methods[tool.name] = {
22
+ name: tool.name,
23
+ description: tool.description || '',
24
+ parameters: tool.inputSchema.properties,
25
+ dependencies: [],
26
+ };
27
+ // @ts-ignore
28
+ this[`_tool_${tool.name}`] = async (request) => {
29
+ this.logger.debug('Calling MCP tool: ' + tool.name, request);
30
+ const params = request.params;
31
+ const result = await this.mcpClient.callTool({
32
+ name: tool.name,
33
+ arguments: params,
34
+ });
35
+ this.logger.debug('MCP tool result: ', result);
36
+ if (result.isError) {
37
+ throw new oToolError(oToolErrorCodes.TOOL_ERROR, JSON.stringify(result.content));
38
+ }
39
+ return result.content;
40
+ };
41
+ });
42
+ await this.startChildren();
43
+ }
44
+ async myTools() {
45
+ const tools = await this.mcpClient.listTools();
46
+ return tools.tools.map((tool) => {
47
+ return tool.name;
48
+ });
49
+ }
50
+ // let's customize the index functionality to ensure we capture MCP insights
51
+ async index() {
52
+ const result = await super.index();
53
+ // add each mcp tool to the vector store
54
+ const tools = await this.mcpClient.listTools();
55
+ await Promise.all(tools.tools.map((tool) => {
56
+ return this.use(new oAddress('o://vector-store'), {
57
+ method: 'add_documents',
58
+ params: {
59
+ documents: [
60
+ {
61
+ pageContent: tool.description,
62
+ metadata: {
63
+ address: this.address?.toString() + '/' + tool.name,
64
+ id: uuidv4(),
65
+ },
66
+ },
67
+ ],
68
+ },
69
+ });
70
+ })).catch((err) => {
71
+ this.logger.error('Error adding MCP tools to vector store: ', err);
72
+ });
73
+ return result;
74
+ }
75
+ async whoami() {
76
+ // do nothing
77
+ const tools = await this.mcpClient.listTools();
78
+ return {
79
+ tools: tools.tools.map((tool) => {
80
+ this.logger.debug('MCP Tool Definition: ', tool.name, tool.description, tool.inputSchema);
81
+ return {
82
+ name: tool.name,
83
+ description: tool.description,
84
+ inputSchema: tool.inputSchema.properties,
85
+ };
86
+ }),
87
+ };
88
+ }
89
+ }
@@ -0,0 +1,5 @@
1
+ import { oMethod } from '@olane/o-protocol';
2
+ export declare const MCP_BRIDGE_METHODS: {
3
+ [key: string]: oMethod;
4
+ };
5
+ //# sourceMappingURL=mcp-bridge.methods.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-bridge.methods.d.ts","sourceRoot":"","sources":["../../../src/methods/mcp-bridge.methods.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C,eAAO,MAAM,kBAAkB,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAkExD,CAAC"}
@@ -0,0 +1,65 @@
1
+ export const MCP_BRIDGE_METHODS = {
2
+ validate_url: {
3
+ name: 'validate_url',
4
+ description: 'Validate if a URL is a valid MCP server or a link to something else.',
5
+ dependencies: [],
6
+ parameters: [
7
+ {
8
+ name: 'mcpServerUrl',
9
+ type: 'string',
10
+ value: 'string',
11
+ description: 'The URL of the MCP server to validate',
12
+ required: true,
13
+ },
14
+ ],
15
+ },
16
+ add_remote_server: {
17
+ name: 'add_remote_server',
18
+ description: 'Add a MCP server that is hosted on a remote server',
19
+ dependencies: [],
20
+ parameters: [
21
+ {
22
+ name: 'mcpServerUrl',
23
+ type: 'string',
24
+ value: 'string',
25
+ description: 'The URL of the MCP server to use',
26
+ required: true,
27
+ },
28
+ {
29
+ name: 'headers',
30
+ type: 'object',
31
+ value: 'Record<string, string>',
32
+ description: 'The headers to send to the MCP server',
33
+ required: false,
34
+ },
35
+ ],
36
+ },
37
+ add_local_server: {
38
+ name: 'add_local_server',
39
+ description: 'Add a local MCP server to the bridge using command and arguments',
40
+ dependencies: [],
41
+ parameters: [
42
+ {
43
+ name: 'command',
44
+ type: 'string',
45
+ value: 'string',
46
+ description: 'The command to execute for the local MCP server',
47
+ required: true,
48
+ },
49
+ {
50
+ name: 'args',
51
+ type: 'array',
52
+ value: 'string[]',
53
+ description: 'The arguments to pass to the command',
54
+ required: true,
55
+ },
56
+ {
57
+ name: 'name',
58
+ type: 'string',
59
+ value: 'string',
60
+ description: 'The name for the MCP server',
61
+ required: true,
62
+ },
63
+ ],
64
+ },
65
+ };
@@ -0,0 +1,15 @@
1
+ import { Client, ClientOptions } from '@modelcontextprotocol/sdk/client/index.js';
2
+ import { Implementation } from '@modelcontextprotocol/sdk/types.js';
3
+ import { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';
4
+ import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
5
+ import { IntentValue } from './o-transport.mcp';
6
+ export type oClientOptions = ClientOptions & {
7
+ /** Value placed into `params._meta.intent` for every outgoing request/notification */
8
+ intent?: IntentValue | (() => IntentValue);
9
+ };
10
+ export declare class oClient extends Client {
11
+ private providedIntent?;
12
+ constructor(_clientInfo: Implementation, options?: oClientOptions);
13
+ connect(transport: Transport, options?: RequestOptions): Promise<void>;
14
+ }
15
+ //# sourceMappingURL=o-client.mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-client.mcp.d.ts","sourceRoot":"","sources":["../../src/o-client.mcp.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,MAAM,EACN,aAAa,EACd,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAEL,cAAc,EAEf,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,8CAA8C,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAC1E,OAAO,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC;AAEzE,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG;IAC3C,sFAAsF;IACtF,MAAM,CAAC,EAAE,WAAW,GAAG,CAAC,MAAM,WAAW,CAAC,CAAC;CAC5C,CAAC;AAEF,qBAAa,OAAQ,SAAQ,MAAM;IACjC,OAAO,CAAC,cAAc,CAAC,CAAoC;gBAE/C,WAAW,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc;IAK3D,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ7E"}
@@ -0,0 +1,15 @@
1
+ import { Client, } from '@modelcontextprotocol/sdk/client/index.js';
2
+ import { IntentWrappingTransport } from './o-transport.mcp';
3
+ export class oClient extends Client {
4
+ constructor(_clientInfo, options) {
5
+ super(_clientInfo, options);
6
+ this.providedIntent = options?.intent;
7
+ }
8
+ async connect(transport, options) {
9
+ const getIntent = () => typeof this.providedIntent === 'function'
10
+ ? this.providedIntent()
11
+ : this.providedIntent;
12
+ const wrapped = new IntentWrappingTransport(transport, getIntent);
13
+ return super.connect(wrapped, options);
14
+ }
15
+ }
@@ -0,0 +1,13 @@
1
+ import { Server, ServerOptions } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { Implementation } from '@modelcontextprotocol/sdk/types.js';
3
+ import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
4
+ export type oServerOptions = ServerOptions & {
5
+ /** Validate that all incoming requests include `_meta.intent` */
6
+ requireIntent?: boolean;
7
+ };
8
+ export declare class oServer extends Server {
9
+ private requireIntent;
10
+ constructor(_serverInfo: Implementation, options?: oServerOptions);
11
+ connect(transport: Transport): Promise<void>;
12
+ }
13
+ //# sourceMappingURL=o-server.mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-server.mcp.d.ts","sourceRoot":"","sources":["../../src/o-server.mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,aAAa,EACd,MAAM,2CAA2C,CAAC;AACnD,OAAO,EAEL,cAAc,EAEf,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAG1E,MAAM,MAAM,cAAc,GAAG,aAAa,GAAG;IAC3C,iEAAiE;IACjE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,qBAAa,OAAQ,SAAQ,MAAM;IACjC,OAAO,CAAC,aAAa,CAAU;gBAEnB,WAAW,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,cAAc;IAK3D,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;CAenD"}
@@ -0,0 +1,23 @@
1
+ import { Server, } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { IntentWrappingTransport } from './o-transport.mcp';
3
+ export class oServer extends Server {
4
+ constructor(_serverInfo, options) {
5
+ super(_serverInfo, options);
6
+ this.requireIntent = !!options?.requireIntent;
7
+ }
8
+ async connect(transport) {
9
+ const wrapped = new IntentWrappingTransport(transport, () => undefined);
10
+ // Install a fallback request handler to enforce intent if requested
11
+ if (this.requireIntent) {
12
+ const prevFallback = this.fallbackRequestHandler;
13
+ this.fallbackRequestHandler = async (req, extra) => {
14
+ const meta = req?.params?._meta || extra._meta || {};
15
+ if (typeof meta.intent === 'undefined') {
16
+ throw new Error('Missing required _meta.intent');
17
+ }
18
+ return prevFallback ? prevFallback(req, extra) : {};
19
+ };
20
+ }
21
+ return super.connect(wrapped);
22
+ }
23
+ }
@@ -0,0 +1,17 @@
1
+ import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
2
+ import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
3
+ export type IntentValue = unknown;
4
+ export declare class IntentWrappingTransport implements Transport {
5
+ private inner;
6
+ private getIntent;
7
+ onclose?: () => void;
8
+ onerror?: (error: Error) => void;
9
+ onmessage?: (message: JSONRPCMessage) => void;
10
+ sessionId?: string;
11
+ setProtocolVersion?: (version: string) => void;
12
+ constructor(inner: Transport, getIntent: () => IntentValue | undefined);
13
+ start(): Promise<void>;
14
+ send(message: JSONRPCMessage): Promise<void>;
15
+ close(): Promise<void>;
16
+ }
17
+ //# sourceMappingURL=o-transport.mcp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"o-transport.mcp.d.ts","sourceRoot":"","sources":["../../src/o-transport.mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EAEf,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAE1E,MAAM,MAAM,WAAW,GAAG,OAAO,CAAC;AAElC,qBAAa,uBAAwB,YAAW,SAAS;IACvD,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,SAAS,CAAgC;IACjD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;gBAEnC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,GAAG,SAAS;IAqBhE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAyB5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -0,0 +1,55 @@
1
+ import { isJSONRPCRequest, } from '@modelcontextprotocol/sdk/types.js';
2
+ export class IntentWrappingTransport {
3
+ constructor(inner, getIntent) {
4
+ this.inner = inner;
5
+ this.getIntent = getIntent;
6
+ // plumb events through
7
+ this.inner.onclose = () => this.onclose && this.onclose();
8
+ this.inner.onerror = (err) => this.onerror && this.onerror(err);
9
+ this.inner.onmessage = (message, extra) => {
10
+ // Enforce presence of intent for incoming requests (server-side usage)
11
+ if (isJSONRPCRequest(message)) {
12
+ const params = message.params || {};
13
+ const meta = params._meta || {};
14
+ if (typeof meta.intent === 'undefined') {
15
+ // If the protocol has installed a handler, let it decide; otherwise, drop-through.
16
+ // We do not auto-respond here to avoid interfering with the protocol; enforcement should be done at handlers.
17
+ }
18
+ }
19
+ this.onmessage && this.onmessage(message);
20
+ };
21
+ }
22
+ async start() {
23
+ await this.inner.start();
24
+ this.sessionId = this.inner.sessionId;
25
+ this.setProtocolVersion = this.inner.setProtocolVersion;
26
+ }
27
+ async send(message) {
28
+ try {
29
+ // Inject `_meta.intent` for outgoing requests/notifications
30
+ const m = message;
31
+ if (m && typeof m === 'object') {
32
+ const hasParams = typeof m.params === 'object' && m.params !== null;
33
+ if (!hasParams) {
34
+ m.params = {};
35
+ }
36
+ if (typeof m.params._meta !== 'object' || m.params._meta === null) {
37
+ m.params._meta = {};
38
+ }
39
+ if (typeof m.params._meta.intent === 'undefined') {
40
+ const intent = this.getIntent();
41
+ if (typeof intent !== 'undefined') {
42
+ m.params._meta.intent = intent;
43
+ }
44
+ }
45
+ }
46
+ }
47
+ catch (_) {
48
+ // Best-effort injection; ignore errors and proceed
49
+ }
50
+ return this.inner.send(message);
51
+ }
52
+ async close() {
53
+ await this.inner.close();
54
+ }
55
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=benchmark.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"benchmark.spec.d.ts","sourceRoot":"","sources":["../../test/benchmark.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,48 @@
1
+ import { expect } from 'chai';
2
+ import { GITHUB_TEST_CASES } from './benchmarks/github/github.test-cases.js';
3
+ import { McpBridgeTool } from '../src/index.js';
4
+ import { NodeState } from '@olane/o-core';
5
+ import { IntelligenceTool } from '@olane/o-intelligence';
6
+ import { oLeaderNode } from '@olane/o-leader';
7
+ const leader = new oLeaderNode({
8
+ parent: null,
9
+ leader: null,
10
+ });
11
+ const mcpTool = new McpBridgeTool({
12
+ parent: null,
13
+ leader: null,
14
+ });
15
+ leader.addChildNode(mcpTool);
16
+ const intelligenceTool = new IntelligenceTool({
17
+ parent: mcpTool.address,
18
+ leader: mcpTool.address,
19
+ });
20
+ leader.addChildNode(intelligenceTool);
21
+ describe('o-mcp start node', () => {
22
+ it('should be able to start a node', async () => {
23
+ await leader.start();
24
+ expect(mcpTool.state).to.equal(NodeState.RUNNING);
25
+ });
26
+ });
27
+ describe('o-mcp github-benchmarks', () => {
28
+ it('should be able to test github benchmarks', async () => {
29
+ for (const testCase of GITHUB_TEST_CASES) {
30
+ console.log(testCase.input);
31
+ const handshakeResponse = await mcpTool.use(mcpTool.address, {
32
+ method: 'handshake',
33
+ params: {
34
+ intent: testCase.input,
35
+ },
36
+ });
37
+ console.log(handshakeResponse.result.data);
38
+ // const result = await testCase.output;
39
+ // expect(result).to.contain(testCase.output.contains);
40
+ }
41
+ });
42
+ });
43
+ describe('o-mcp stop node', () => {
44
+ it('should be able to stop a node', async () => {
45
+ await leader.stop();
46
+ expect(mcpTool.state).to.equal(NodeState.STOPPED);
47
+ });
48
+ });
@@ -0,0 +1,3 @@
1
+ import { TestCase } from '../interfaces/test-case.interface';
2
+ export declare const GITHUB_TEST_CASES: TestCase[];
3
+ //# sourceMappingURL=github.test-cases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.test-cases.d.ts","sourceRoot":"","sources":["../../../../test/benchmarks/github/github.test-cases.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAE7D,eAAO,MAAM,iBAAiB,EAAE,QAAQ,EAUvC,CAAC"}
@@ -0,0 +1,10 @@
1
+ export const GITHUB_TEST_CASES = [
2
+ {
3
+ name: 'github-001',
4
+ description: 'Test case for creating a new repository with 3 branches and a PR',
5
+ input: `Hey! I need to set up a new repo for this travel planner project I'm working on. Can you help me create a repository called travel-planner-app? I need to start with 3 branches: main, feature-maps, and feature-itinerary. \n\nFor the README.md on main, can you add this content: \"# Travel Planner App\n\nA comprehensive travel planning application that helps users organize their trips, find attractions, and discover local restaurants.\"\n\nI also need an app.js file on the feature-itinerary branch with this basic Express setup: \"// Main application entry point\nconst express = require('express');\nconst app = express();\n\napp.get('/', (req, res) => {\n res.send('Welcome to Travel Planner!');\n});\n\napp.listen(3000, () => {\n console.log('Server running on port 3000');\n});\"\n\nOh, and don't forget a .gitignore file on main with: \"# Node dependencies\nnode_modules/\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Python cache and virtual environments\n__pycache__/\n*.pyc\n*.py.class\nvenv/\n*.env\"\n\nI found this budget_estimation.py file in the OSU NLP Group's TravelPlanner repo that might be useful. Can you copy it to the feature-maps branch? \n\nLastly, I'd like to create a PR from feature-itinerary to main. Title it \"Add basic Express server setup\" and for the description: \"This PR implements the initial Express server configuration with a basic route handler for the homepage.\" Thanks!`,
6
+ output: {
7
+ contains: 'a',
8
+ },
9
+ },
10
+ ];
@@ -0,0 +1,10 @@
1
+ export interface TestCase {
2
+ name: string;
3
+ description: string;
4
+ input: string;
5
+ output: {
6
+ contains?: string;
7
+ matches?: string;
8
+ };
9
+ }
10
+ //# sourceMappingURL=test-case.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-case.interface.d.ts","sourceRoot":"","sources":["../../../../test/benchmarks/interfaces/test-case.interface.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE;QACN,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH"}
@@ -0,0 +1,2 @@
1
+ export declare const MCP_REPO: string[];
2
+ //# sourceMappingURL=mcp-repo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-repo.d.ts","sourceRoot":"","sources":["../../../test/utils/mcp-repo.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,QAAQ,UAIpB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export const MCP_REPO = [
2
+ `Add https://api.githubcopilot.com/mcp/ with API key: ${process.env.GITHUB_API_KEY}`,
3
+ `Add MCP server: "command": "uvx" and "args": ["mcp-server-time"]`,
4
+ ``,
5
+ ];
@@ -0,0 +1,9 @@
1
+ export declare const MODELS: {
2
+ ollama: string[];
3
+ openai: string[];
4
+ anthropic: string[];
5
+ google: string[];
6
+ deepseek: string[];
7
+ xAi: string[];
8
+ };
9
+ //# sourceMappingURL=models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../../test/utils/models.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;;;;;;;CAOlB,CAAC"}
@@ -0,0 +1,8 @@
1
+ export const MODELS = {
2
+ ollama: ['llama3.2:latest', 'deepseek-r1:7b'],
3
+ openai: ['gpt-4o', 'gpt-4o-mini', 'gpt-5'],
4
+ anthropic: ['claude-3.5-sonnet', 'claude-3.5-sonnet-20240620'],
5
+ google: ['gemini-2.0-flash-001', 'gemini-2.0-flash-001-8b'],
6
+ deepseek: ['deepseek-r1', 'deepseek-r1-8b'],
7
+ xAi: ['grok-4-0709', 'grok-3-mini', 'grok-3-fast'],
8
+ };
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@olane/o-mcp",
3
+ "version": "0.6.1",
4
+ "type": "module",
5
+ "main": "dist/src/index.js",
6
+ "types": "dist/src/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/src/index.d.ts",
10
+ "default": "./dist/src/index.js"
11
+ }
12
+ },
13
+ "files": [
14
+ "dist/**/*",
15
+ "README.md",
16
+ "LICENSE"
17
+ ],
18
+ "scripts": {
19
+ "test": "aegir test",
20
+ "test:node": "aegir test -t node",
21
+ "test:browser": "aegir test -t browser",
22
+ "dev": "DEBUG=o-protocol:* npx tsx src/tests/index.ts",
23
+ "build": "tsc",
24
+ "deep:clean": "rm -rf node_modules && rm package-lock.json",
25
+ "start:prod": "node dist/index.js",
26
+ "prepublishOnly": "npm run build",
27
+ "update:lib": "npm install @olane/o-core@latest",
28
+ "lint": "eslint src/**/*.ts"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/olane-labs/olane.git"
33
+ },
34
+ "author": "oLane Inc.",
35
+ "license": "ISC",
36
+ "description": "oLane Core",
37
+ "devDependencies": {
38
+ "@olane/o-config": "file:../o-config",
39
+ "@olane/o-core": "file:../..",
40
+ "@olane/o-protocol": "file:../o-protocol",
41
+ "@olane/o-tool": "file:../o-tool",
42
+ "@olane/o-leader": "file:../o-leader",
43
+ "@olane/o-intelligence": "file:../o-intelligence",
44
+ "@eslint/eslintrc": "^3.3.1",
45
+ "@eslint/js": "^9.29.0",
46
+ "@tsconfig/node20": "^20.1.6",
47
+ "@types/jest": "^30.0.0",
48
+ "@typescript-eslint/eslint-plugin": "^8.34.1",
49
+ "@typescript-eslint/parser": "^8.34.1",
50
+ "eslint": "^9.29.0",
51
+ "eslint-config-prettier": "^10.1.6",
52
+ "eslint-plugin-prettier": "^5.5.0",
53
+ "globals": "^16.2.0",
54
+ "jest": "^30.0.0",
55
+ "prettier": "^3.5.3",
56
+ "ts-jest": "^29.4.0",
57
+ "ts-node": "^10.9.2",
58
+ "tsconfig-paths": "^4.2.0",
59
+ "tsx": "^4.20.3",
60
+ "typescript": "5.4.5"
61
+ },
62
+ "peerDependencies": {
63
+ "@olane/o-config": "^0.6.1",
64
+ "@olane/o-core": "^0.6.1",
65
+ "@olane/o-protocol": "^0.6.1",
66
+ "@olane/o-tool": "^0.6.1",
67
+ "@olane/o-leader": "^0.6.1",
68
+ "@modelcontextprotocol/sdk": "^1.13.0"
69
+ },
70
+ "dependencies": {
71
+ "debug": "^4.4.1",
72
+ "dotenv": "^16.5.0"
73
+ }
74
+ }