@blueberrybytes/webmcp 0.1.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.
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ /**
3
+ * MCP Server - Implementation of MCP protocol for WebMCP
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MCPServer = void 0;
7
+ const json_rpc_2_0_1 = require("json-rpc-2.0");
8
+ const model_context_1 = require("./model-context");
9
+ /**
10
+ * MCP Server that handles JSON-RPC communication for WebMCP tools
11
+ */
12
+ class MCPServer {
13
+ constructor(modelContext) {
14
+ this.clients = new Map();
15
+ this.server = new json_rpc_2_0_1.JSONRPCServer();
16
+ this.modelContext = modelContext || new model_context_1.ModelContext();
17
+ this.setupMethods();
18
+ }
19
+ /**
20
+ * Sets up the JSON-RPC methods for the MCP server
21
+ */
22
+ setupMethods() {
23
+ // List available tools
24
+ this.server.addMethod('tools/list', () => {
25
+ const tools = this.modelContext.getAllTools();
26
+ return {
27
+ tools: tools.map(tool => ({
28
+ name: tool.name,
29
+ description: tool.description,
30
+ inputSchema: tool.inputSchema
31
+ }))
32
+ };
33
+ });
34
+ // Execute a tool
35
+ this.server.addMethod('tools/call', async (params) => {
36
+ const { name, arguments: args } = params;
37
+ const client = this.getDefaultClient();
38
+ try {
39
+ const result = await this.modelContext.executeTool(name, args || {}, client);
40
+ return this.formatToolResult(result);
41
+ }
42
+ catch (error) {
43
+ throw {
44
+ code: -32603,
45
+ message: error instanceof Error ? error.message : 'Internal error',
46
+ data: error
47
+ };
48
+ }
49
+ });
50
+ // Get tool by name
51
+ this.server.addMethod('tools/get', (params) => {
52
+ const { name } = params;
53
+ const tool = this.modelContext.getTool(name);
54
+ if (!tool) {
55
+ throw {
56
+ code: -32601,
57
+ message: `Tool '${name}' not found`
58
+ };
59
+ }
60
+ return {
61
+ name: tool.name,
62
+ description: tool.description,
63
+ inputSchema: tool.inputSchema
64
+ };
65
+ });
66
+ }
67
+ /**
68
+ * Handles incoming JSON-RPC requests
69
+ * @param request - The JSON-RPC request
70
+ * @param clientId - Optional client ID
71
+ * @returns Promise that resolves with the JSON-RPC response
72
+ */
73
+ async receive(request, clientId) {
74
+ return await this.server.receive(request);
75
+ }
76
+ /**
77
+ * Adds a tool to the model context
78
+ * @param tool - The tool to add
79
+ */
80
+ addTool(tool) {
81
+ this.modelContext.registerTool(tool);
82
+ }
83
+ /**
84
+ * Removes a tool from the model context
85
+ * @param name - The name of the tool to remove
86
+ */
87
+ removeTool(name) {
88
+ this.modelContext.unregisterTool(name);
89
+ }
90
+ /**
91
+ * Gets all registered tools
92
+ * @returns Array of all registered tools
93
+ */
94
+ getTools() {
95
+ return this.modelContext.getAllTools();
96
+ }
97
+ /**
98
+ * Gets the model context
99
+ * @returns The model context
100
+ */
101
+ getModelContext() {
102
+ return this.modelContext;
103
+ }
104
+ /**
105
+ * Adds a client to the server
106
+ * @param clientId - The client ID
107
+ * @param client - The client to add
108
+ */
109
+ addClient(clientId, client) {
110
+ this.clients.set(clientId, client);
111
+ }
112
+ /**
113
+ * Removes a client from the server
114
+ * @param clientId - The client ID to remove
115
+ */
116
+ removeClient(clientId) {
117
+ this.clients.delete(clientId);
118
+ }
119
+ /**
120
+ * Gets a client by ID
121
+ * @param clientId - The client ID
122
+ * @returns The client or undefined if not found
123
+ */
124
+ getClient(clientId) {
125
+ return this.clients.get(clientId);
126
+ }
127
+ /**
128
+ * Gets the default client
129
+ * @returns The default client
130
+ */
131
+ getDefaultClient() {
132
+ return {
133
+ requestUserInteraction: async (callback) => {
134
+ // In a real implementation, this would handle user interaction
135
+ // For now, we'll just execute the callback
136
+ return await callback();
137
+ }
138
+ };
139
+ }
140
+ /**
141
+ * Formats a tool result for MCP protocol
142
+ * @param result - The tool result
143
+ * @returns Formatted result
144
+ */
145
+ formatToolResult(result) {
146
+ // If result is already in the correct format, return it
147
+ if (result && typeof result === 'object' && (result.content || result.type)) {
148
+ return result;
149
+ }
150
+ // If result is a string, wrap it in the appropriate format
151
+ if (typeof result === 'string') {
152
+ return {
153
+ content: [
154
+ {
155
+ type: 'text',
156
+ text: result
157
+ }
158
+ ]
159
+ };
160
+ }
161
+ // If result is an object, try to convert it to a string representation
162
+ if (typeof result === 'object' && result !== null) {
163
+ return {
164
+ content: [
165
+ {
166
+ type: 'text',
167
+ text: JSON.stringify(result, null, 2)
168
+ }
169
+ ]
170
+ };
171
+ }
172
+ // For other types, convert to string
173
+ return {
174
+ content: [
175
+ {
176
+ type: 'text',
177
+ text: String(result)
178
+ }
179
+ ]
180
+ };
181
+ }
182
+ }
183
+ exports.MCPServer = MCPServer;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * ModelContext - Implementation of the WebMCP API
3
+ */
4
+ import { ModelContextTool, ModelContextOptions, ModelContextClient } from './types';
5
+ /**
6
+ * ModelContext provides methods for web applications to register and manage tools
7
+ * that can be invoked by AI agents
8
+ */
9
+ export declare class ModelContext {
10
+ private tools;
11
+ private sessionId;
12
+ constructor();
13
+ /**
14
+ * Registers the provided context (tools) with the browser
15
+ * This method clears any pre-existing tools and other context before registering the new ones
16
+ * @param options - Options containing tools to register
17
+ */
18
+ provideContext(options?: ModelContextOptions): void;
19
+ /**
20
+ * Unregisters all context (tools) with the browser
21
+ */
22
+ clearContext(): void;
23
+ /**
24
+ * Registers a single tool without clearing the existing set of tools
25
+ * @param tool - The tool to register
26
+ * @throws Error if a tool with the same name already exists
27
+ */
28
+ registerTool(tool: ModelContextTool): void;
29
+ /**
30
+ * Removes the tool with the specified name from the registered set
31
+ * @param name - The name of the tool to unregister
32
+ */
33
+ unregisterTool(name: string): void;
34
+ /**
35
+ * Gets a tool by name
36
+ * @param name - The name of the tool to retrieve
37
+ * @returns The tool or undefined if not found
38
+ */
39
+ getTool(name: string): ModelContextTool | undefined;
40
+ /**
41
+ * Gets all registered tools
42
+ * @returns Array of all registered tools
43
+ */
44
+ getAllTools(): ModelContextTool[];
45
+ /**
46
+ * Executes a tool by name with the provided input
47
+ * @param name - The name of the tool to execute
48
+ * @param input - The input parameters for the tool
49
+ * @param client - The client executing the tool
50
+ * @returns Promise that resolves with the tool result
51
+ */
52
+ executeTool(name: string, input: Record<string, any>, client: ModelContextClient): Promise<any>;
53
+ /**
54
+ * Gets tools filtered by category
55
+ * @param category - The category to filter by
56
+ * @returns Array of tools in the specified category
57
+ */
58
+ getToolsByCategory(category: string): ModelContextTool[];
59
+ /**
60
+ * Gets tools filtered by tags
61
+ * @param tags - The tags to filter by
62
+ * @returns Array of tools with the specified tags
63
+ */
64
+ getToolsByTags(tags: string[]): ModelContextTool[];
65
+ /**
66
+ * Gets the session ID for this context
67
+ * @returns The session ID
68
+ */
69
+ getSessionId(): string;
70
+ /**
71
+ * Validates input against a JSON schema
72
+ * @param input - The input to validate
73
+ * @param schema - The schema to validate against
74
+ */
75
+ private validateInput;
76
+ /**
77
+ * Checks if a value is of the correct type
78
+ * @param value - The value to check
79
+ * @param expectedType - The expected type
80
+ * @returns True if the value is of the correct type
81
+ */
82
+ private isCorrectType;
83
+ /**
84
+ * Validates a JSON schema
85
+ * @param schema - The schema to validate
86
+ * @returns True if the schema is valid
87
+ */
88
+ private isValidSchema;
89
+ /**
90
+ * Generates a unique session ID
91
+ * @returns A unique session ID
92
+ */
93
+ private generateSessionId;
94
+ }
@@ -0,0 +1,199 @@
1
+ "use strict";
2
+ /**
3
+ * ModelContext - Implementation of the WebMCP API
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ModelContext = void 0;
7
+ /**
8
+ * ModelContext provides methods for web applications to register and manage tools
9
+ * that can be invoked by AI agents
10
+ */
11
+ class ModelContext {
12
+ constructor() {
13
+ this.tools = new Map();
14
+ // Generate a unique session ID for this context
15
+ this.sessionId = this.generateSessionId();
16
+ }
17
+ /**
18
+ * Registers the provided context (tools) with the browser
19
+ * This method clears any pre-existing tools and other context before registering the new ones
20
+ * @param options - Options containing tools to register
21
+ */
22
+ provideContext(options = {}) {
23
+ // Clear existing tools
24
+ this.clearContext();
25
+ // Register new tools if provided
26
+ if (options.tools && options.tools.length > 0) {
27
+ for (const tool of options.tools) {
28
+ this.registerTool(tool);
29
+ }
30
+ }
31
+ }
32
+ /**
33
+ * Unregisters all context (tools) with the browser
34
+ */
35
+ clearContext() {
36
+ this.tools.clear();
37
+ }
38
+ /**
39
+ * Registers a single tool without clearing the existing set of tools
40
+ * @param tool - The tool to register
41
+ * @throws Error if a tool with the same name already exists
42
+ */
43
+ registerTool(tool) {
44
+ if (this.tools.has(tool.name)) {
45
+ throw new Error(`Tool with name '${tool.name}' already exists`);
46
+ }
47
+ // Validate input schema if provided
48
+ if (tool.inputSchema && !this.isValidSchema(tool.inputSchema)) {
49
+ throw new Error(`Invalid input schema for tool '${tool.name}'`);
50
+ }
51
+ this.tools.set(tool.name, tool);
52
+ }
53
+ /**
54
+ * Removes the tool with the specified name from the registered set
55
+ * @param name - The name of the tool to unregister
56
+ */
57
+ unregisterTool(name) {
58
+ this.tools.delete(name);
59
+ }
60
+ /**
61
+ * Gets a tool by name
62
+ * @param name - The name of the tool to retrieve
63
+ * @returns The tool or undefined if not found
64
+ */
65
+ getTool(name) {
66
+ return this.tools.get(name);
67
+ }
68
+ /**
69
+ * Gets all registered tools
70
+ * @returns Array of all registered tools
71
+ */
72
+ getAllTools() {
73
+ return Array.from(this.tools.values());
74
+ }
75
+ /**
76
+ * Executes a tool by name with the provided input
77
+ * @param name - The name of the tool to execute
78
+ * @param input - The input parameters for the tool
79
+ * @param client - The client executing the tool
80
+ * @returns Promise that resolves with the tool result
81
+ */
82
+ async executeTool(name, input, client) {
83
+ const tool = this.getTool(name);
84
+ if (!tool) {
85
+ throw new Error(`Tool '${name}' not found`);
86
+ }
87
+ // Validate input against schema if provided
88
+ if (tool.inputSchema) {
89
+ this.validateInput(input, tool.inputSchema);
90
+ }
91
+ // Execute the tool
92
+ return await tool.execute(input, client);
93
+ }
94
+ /**
95
+ * Gets tools filtered by category
96
+ * @param category - The category to filter by
97
+ * @returns Array of tools in the specified category
98
+ */
99
+ getToolsByCategory(category) {
100
+ return Array.from(this.tools.values()).filter(tool => tool.annotations?.category === category);
101
+ }
102
+ /**
103
+ * Gets tools filtered by tags
104
+ * @param tags - The tags to filter by
105
+ * @returns Array of tools with the specified tags
106
+ */
107
+ getToolsByTags(tags) {
108
+ return Array.from(this.tools.values()).filter(tool => {
109
+ const toolTags = tool.annotations?.tags || [];
110
+ return tags.some(tag => toolTags.includes(tag));
111
+ });
112
+ }
113
+ /**
114
+ * Gets the session ID for this context
115
+ * @returns The session ID
116
+ */
117
+ getSessionId() {
118
+ return this.sessionId;
119
+ }
120
+ /**
121
+ * Validates input against a JSON schema
122
+ * @param input - The input to validate
123
+ * @param schema - The schema to validate against
124
+ */
125
+ validateInput(input, schema) {
126
+ // Check required properties
127
+ if (schema.required && Array.isArray(schema.required)) {
128
+ for (const requiredProp of schema.required) {
129
+ if (!(requiredProp in input)) {
130
+ throw new Error(`Missing required property: ${requiredProp}`);
131
+ }
132
+ }
133
+ }
134
+ // Check property types if schema defines them
135
+ if (schema.properties) {
136
+ for (const [propName, propSchema] of Object.entries(schema.properties)) {
137
+ if (propName in input) {
138
+ const value = input[propName];
139
+ const expectedType = propSchema.type;
140
+ if (expectedType) {
141
+ if (!this.isCorrectType(value, expectedType)) {
142
+ throw new Error(`Property '${propName}' should be of type '${expectedType}'`);
143
+ }
144
+ }
145
+ }
146
+ }
147
+ }
148
+ }
149
+ /**
150
+ * Checks if a value is of the correct type
151
+ * @param value - The value to check
152
+ * @param expectedType - The expected type
153
+ * @returns True if the value is of the correct type
154
+ */
155
+ isCorrectType(value, expectedType) {
156
+ switch (expectedType) {
157
+ case 'string':
158
+ return typeof value === 'string';
159
+ case 'number':
160
+ return typeof value === 'number';
161
+ case 'boolean':
162
+ return typeof value === 'boolean';
163
+ case 'object':
164
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
165
+ case 'array':
166
+ return Array.isArray(value);
167
+ default:
168
+ return true; // Allow any type if not specifically checked
169
+ }
170
+ }
171
+ /**
172
+ * Validates a JSON schema
173
+ * @param schema - The schema to validate
174
+ * @returns True if the schema is valid
175
+ */
176
+ isValidSchema(schema) {
177
+ // Basic validation - check that it's an object
178
+ if (typeof schema !== 'object' || schema === null) {
179
+ return false;
180
+ }
181
+ // If properties are defined, they should be an object
182
+ if (schema.properties && typeof schema.properties !== 'object') {
183
+ return false;
184
+ }
185
+ // If required is defined, it should be an array
186
+ if (schema.required && !Array.isArray(schema.required)) {
187
+ return false;
188
+ }
189
+ return true;
190
+ }
191
+ /**
192
+ * Generates a unique session ID
193
+ * @returns A unique session ID
194
+ */
195
+ generateSessionId() {
196
+ return 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
197
+ }
198
+ }
199
+ exports.ModelContext = ModelContext;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * ToolManager - Utility class for managing WebMCP tools
3
+ */
4
+ import { ModelContextTool, JSONSchema, ToolAnnotations } from './types';
5
+ import { ModelContext } from './model-context';
6
+ /**
7
+ * ToolManager provides utilities for registering and managing WebMCP tools
8
+ */
9
+ export declare class ToolManager {
10
+ private modelContext;
11
+ constructor(modelContext: ModelContext);
12
+ /**
13
+ * Creates a new tool with the specified parameters
14
+ * @param name - The name of the tool
15
+ * @param description - The description of the tool
16
+ * @param execute - The execute function for the tool
17
+ * @param options - Additional options for the tool
18
+ * @returns The created tool
19
+ */
20
+ createTool(name: string, description: string, execute: (input: Record<string, any>, client: any) => Promise<any>, options?: {
21
+ inputSchema?: JSONSchema;
22
+ annotations?: ToolAnnotations;
23
+ }): ModelContextTool;
24
+ /**
25
+ * Registers a tool with the model context
26
+ * @param tool - The tool to register
27
+ * @returns The registered tool
28
+ */
29
+ registerTool(tool: ModelContextTool): ModelContextTool;
30
+ /**
31
+ * Unregisters a tool from the model context
32
+ * @param name - The name of the tool to unregister
33
+ */
34
+ unregisterTool(name: string): void;
35
+ /**
36
+ * Gets a tool by name
37
+ * @param name - The name of the tool to retrieve
38
+ * @returns The tool or undefined if not found
39
+ */
40
+ getTool(name: string): ModelContextTool | undefined;
41
+ /**
42
+ * Gets all registered tools
43
+ * @returns Array of all registered tools
44
+ */
45
+ getAllTools(): ModelContextTool[];
46
+ /**
47
+ * Gets tools filtered by category
48
+ * @param category - The category to filter by
49
+ * @returns Array of tools in the specified category
50
+ */
51
+ getToolsByCategory(category: string): ModelContextTool[];
52
+ /**
53
+ * Gets tools filtered by tags
54
+ * @param tags - The tags to filter by
55
+ * @returns Array of tools with the specified tags
56
+ */
57
+ getToolsByTags(tags: string[]): ModelContextTool[];
58
+ /**
59
+ * Creates a tool with category annotation
60
+ * @param name - The name of the tool
61
+ * @param description - The description of the tool
62
+ * @param category - The category of the tool
63
+ * @param execute - The execute function for the tool
64
+ * @param options - Additional options for the tool
65
+ * @returns The created tool
66
+ */
67
+ createCategorizedTool(name: string, description: string, category: string, execute: (input: Record<string, any>, client: any) => Promise<any>, options?: {
68
+ inputSchema?: JSONSchema;
69
+ tags?: string[];
70
+ }): ModelContextTool;
71
+ /**
72
+ * Creates a tool with authentication requirements
73
+ * @param name - The name of the tool
74
+ * @param description - The description of the tool
75
+ * @param execute - The execute function for the tool
76
+ * @param options - Additional options for the tool
77
+ * @returns The created tool
78
+ */
79
+ createAuthenticatedTool(name: string, description: string, execute: (input: Record<string, any>, client: any) => Promise<any>, options?: {
80
+ inputSchema?: JSONSchema;
81
+ scopes?: string[];
82
+ tags?: string[];
83
+ }): ModelContextTool;
84
+ /**
85
+ * Creates a read-only tool
86
+ * @param name - The name of the tool
87
+ * @param description - The description of the tool
88
+ * @param execute - The execute function for the tool
89
+ * @param options - Additional options for the tool
90
+ * @returns The created tool
91
+ */
92
+ createReadOnlyTool(name: string, description: string, execute: (input: Record<string, any>, client: any) => Promise<any>, options?: {
93
+ inputSchema?: JSONSchema;
94
+ tags?: string[];
95
+ }): ModelContextTool;
96
+ /**
97
+ * Batch registers multiple tools
98
+ * @param tools - Array of tools to register
99
+ * @returns Array of successfully registered tools
100
+ */
101
+ registerTools(tools: ModelContextTool[]): ModelContextTool[];
102
+ /**
103
+ * Validates a tool before registration
104
+ * @param tool - The tool to validate
105
+ * @returns True if the tool is valid, false otherwise
106
+ */
107
+ validateTool(tool: ModelContextTool): boolean;
108
+ }