mcptoolforge 0.1.0__py3-none-any.whl

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,655 @@
1
+ Metadata-Version: 2.5
2
+ Name: mcptoolforge
3
+ Version: 0.1.0
4
+ Summary: A developer-friendly Python framework for creating and exposing MCP tools with minimal boilerplate
5
+ Project-URL: Homepage, https://github.com/mcptoolforge/mcptoolforge
6
+ Project-URL: Repository, https://github.com/mcptoolforge/mcptoolforge
7
+ Project-URL: Issues, https://github.com/mcptoolforge/mcptoolforge/issues
8
+ Author: MCPToolForge Contributors
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Requires-Python: >=3.11
12
+ Requires-Dist: anyio>=4.0
13
+ Requires-Dist: mcp>=2.0.0
14
+ Description-Content-Type: text/markdown
15
+
16
+ # MCPToolForge
17
+
18
+ A developer-friendly Python framework for creating and exposing Model Context Protocol (MCP) tools with minimal boilerplate.
19
+
20
+ ## Project Status
21
+
22
+ **Active Development**
23
+
24
+ MCPToolForge now supports exposing registered Python tools as Model Context Protocol (MCP) tools using the standard low-level `Server` over the process's standard input/output (stdio) streams. Network and SSE transports are planned for upcoming stages.
25
+
26
+ ## What MCPToolForge Solves
27
+
28
+ Exposing Python code as tools for AI/LLM systems currently requires complex boilerplate code or manual JSON Schema definitions. MCPToolForge simplifies this by:
29
+ 1. Inferring tool schemas automatically from Python function signatures and type annotations.
30
+ 2. Managing the registry, validation, and lifecycle of registered callables.
31
+ 3. Decoupling tool execution logic from specific transports.
32
+
33
+ ## Planned Architecture
34
+
35
+ MCPToolForge separates concerns into distinct modules:
36
+ - **`MCPServer`**: Core API server orchestration.
37
+ - **`registry`**: Tracks and maps tools to callables.
38
+ - **`schema`**: Automatically converts function signatures to JSON schemas.
39
+ - **`execution`**: Safely executes tools, handling sync and async functions.
40
+ - **`transports`**: Implements JSON-RPC over stdio, SSE, or custom transport protocols.
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ pip install mcptoolforge
46
+ ```
47
+
48
+ ## Basic Usage
49
+
50
+ ```python
51
+ from mcptoolforge import MCPServer
52
+
53
+ server = MCPServer("my-tools")
54
+
55
+
56
+ @server.tool
57
+ def add(a: int, b: int) -> int:
58
+ """Add two numbers."""
59
+ return a + b
60
+ ```
61
+
62
+ ## Creating a Tool
63
+
64
+ To register a tool on an `MCPServer`, use the `@server.tool` decorator:
65
+
66
+ ```python
67
+ from mcptoolforge import MCPServer
68
+
69
+ server = MCPServer("demo")
70
+
71
+
72
+ @server.tool
73
+ def add(a: int, b: int) -> int:
74
+ """Add two numbers."""
75
+ return a + b
76
+ ```
77
+
78
+ Internally, MCPToolForge handles this registration seamlessly:
79
+
80
+ ```text
81
+ Python function
82
+ ↓
83
+ @server.tool
84
+ ↓
85
+ Tool metadata (name, docstring, parameters, return type)
86
+ ↓
87
+ ToolRegistry
88
+ ```
89
+
90
+ ## Tool Metadata
91
+
92
+ MCPToolForge supports both simple and configured registration styles for tools. This allows you to attach custom names, descriptions, tags, and generic metadata while keeping the decoration interface clean and backward compatible.
93
+
94
+ ### Simple Decorator Style
95
+
96
+ By default, MCPToolForge infers the tool name from the Python function's name and the description from the docstring:
97
+
98
+ ```python
99
+ @server.tool
100
+ def add(a: int, b: int) -> int:
101
+ """Add two numbers."""
102
+ return a + b
103
+ ```
104
+
105
+ ### Configured Decorator Style
106
+
107
+ To specify custom metadata, pass arguments directly to the `@server.tool(...)` decorator:
108
+
109
+ ```python
110
+ @server.tool(
111
+ name="calculator",
112
+ description="Perform arithmetic calculations",
113
+ tags=["math", "utility"],
114
+ metadata={"version": "1.0.0"},
115
+ )
116
+ def calculate(expression: str) -> float:
117
+ """Original docstring is ignored in favor of custom description."""
118
+ ...
119
+ ```
120
+
121
+ ### Metadata Fields and Behaviors
122
+
123
+ - **`name`** (str | None): Custom name exposed to MCP clients. It must be non-empty and match the regex `^[a-zA-Z_][a-zA-Z0-9_-]*$`. If not provided, it defaults to the Python function name. Note that the Python function name and MCP tool name can differ (the function remains callable locally by its original name).
124
+ - **`description`** (str | None): Custom description. Takes precedence over the function's docstring. If both are missing, a fallback description (`"No description provided."`) is used. Empty custom descriptions are rejected.
125
+ - **`tags`** (list[str] | None): Optional list of non-empty strings representing tool categories/tags. Duplicate tags are automatically deduplicated while preserving order.
126
+ - **`metadata`** (dict[str, Any] | None): Optional dictionary of custom JSON-serializable key-value metadata. Core fields (such as `name`, `description`, `tags`, etc.) are restricted from being overridden in this dictionary.
127
+ - **`input_schema`** & **`parameters`**: Automatically generated from the Python signature type annotations. Schema generation remains unaffected by custom metadata.
128
+
129
+ ### Tool Immutability
130
+
131
+ Once a tool is registered, its core metadata (`fn`, `name`, `description`, `parameters`, `return_type`, `tags`, `metadata`) is protected against accidental modifications using read-only properties.
132
+
133
+ ---
134
+
135
+ ## Resources
136
+
137
+ MCPToolForge supports exposing readable data/context through MCP Resources with a simple decorator-based API.
138
+
139
+ ### Difference Between Tools and Resources
140
+
141
+ - **Tools**: AI models *request* the server to perform actions/operations (e.g. write to files, calculate values, send network requests).
142
+ - **Resources**: AI models *query* the server to read information (e.g. configuration states, log entries, file contents).
143
+
144
+ ### Registering Resources
145
+
146
+ To register a resource, use the `@server.resource(uri, ...)` decorator:
147
+
148
+ ```python
149
+ @server.resource(
150
+ "config://app",
151
+ description="Application configuration parameters",
152
+ mime_type="application/json",
153
+ )
154
+ def app_config():
155
+ return {"name": "MCPToolForge", "version": "0.1.0"}
156
+ ```
157
+
158
+ ### Resource URI
159
+
160
+ The URI serves as the unique identifier for the resource.
161
+ - It must be a valid non-empty URI string containing a scheme and either a netloc or a path (e.g., `config://app`, `file:///path/to/doc`).
162
+ - Duplicate URIs will raise `ResourceAlreadyRegisteredError`.
163
+
164
+ ### Resource Name and Description
165
+
166
+ - **`name`** (str | None): Custom human-readable resource name. If not provided, it defaults to the Python function name.
167
+ - **`description`** (str | None): Custom description of the resource. Takes precedence over the function docstring. If both are missing, defaults to `"No description provided."`.
168
+
169
+ ### MIME Type
170
+
171
+ - **`mime_type`** (str | None): Optional MIME type of the returned content. If omitted and the resource returns a dictionary or list, it defaults to `application/json`. Otherwise, it remains unspecified.
172
+
173
+ ### Sync vs Async Resources
174
+
175
+ Both synchronous and asynchronous resource handler callables are supported natively:
176
+
177
+ ```python
178
+ @server.resource("log://active")
179
+ async def read_logs():
180
+ return "Log file content..."
181
+ ```
182
+
183
+ ### Result Serialization
184
+
185
+ Resources return contents mapped to the standard MCP model formats depending on the return type:
186
+ - **`str`**: Mapped to `TextResourceContents` (retains text formatting).
187
+ - **`dict` | `list`**: Automatically serialized to JSON and mapped to `TextResourceContents` (defaults to `application/json` mime type).
188
+ - **`bytes`**: Base64 encoded and mapped to `BlobResourceContents` (binary format).
189
+ - **Other types**: If the return type is not supported, `ResourceExecutionError` is raised.
190
+
191
+ ---
192
+
193
+ > [!NOTE]
194
+ > MCPToolForge is in early development. Standard Model Context Protocol (MCP) transport support (such as stdio JSON-RPC or Server-Sent Events) is upcoming. Currently, registration and tool introspection function locally.
195
+
196
+ ## Automatic Schema Generation
197
+
198
+ MCPToolForge automatically derives JSON Schema inputs from standard Python type annotations and default values. Developers do not need to write JSON schemas manually.
199
+
200
+ For example, given this tool:
201
+
202
+ ```python
203
+ @server.tool
204
+ def search(query: str, limit: int = 10):
205
+ """Search information."""
206
+ ...
207
+ ```
208
+
209
+ MCPToolForge dynamically generates the corresponding input schema:
210
+
211
+ ```json
212
+ {
213
+ "type": "object",
214
+ "properties": {
215
+ "query": {
216
+ "type": "string"
217
+ },
218
+ "limit": {
219
+ "type": "integer",
220
+ "default": 10
221
+ }
222
+ },
223
+ "required": ["query"]
224
+ }
225
+ ```
226
+
227
+ This ensures full type safety and seamless integration with MCP clients out-of-the-box.
228
+
229
+ ## Runtime Validation
230
+
231
+ MCPToolForge verifies incoming arguments against the generated tool schemas during execution. If invalid, missing, or unexpected arguments are supplied, the error is isolated and returned cleanly without crashing the server.
232
+
233
+ ```text
234
+ Tool registration
235
+ ↓
236
+ Schema generation
237
+ ↓
238
+ Runtime argument validation (type safety checks)
239
+ ↓
240
+ Tool execution (sync or async)
241
+ ```
242
+
243
+ For example:
244
+ - **Valid Call**: `add(10, 20)` $\to$ returns `30`.
245
+ - **Missing Parameter**: Calling `add(10)` $\to$ returns error: `Tool 'add': missing required parameter 'b'.`
246
+ - **Invalid Parameter Type**: Calling `add("hello", 20)` $\to$ returns error: `Tool 'add': parameter 'a' expected integer, received str.`
247
+ - **Unexpected Parameter**: Calling `add(10, 20, c=30)` $\to$ returns error: `Tool 'add': unexpected parameter 'c'.`
248
+
249
+
250
+ ## MCP Server
251
+
252
+ MCPToolForge handles the translation and registration of local Python callables as standard Model Context Protocol (MCP) tools:
253
+
254
+ ```text
255
+ @server.tool
256
+ ↓
257
+ Tool registration (ToolRegistry)
258
+ ↓
259
+ Schema generation (input_schema)
260
+ ↓
261
+ MCP tool exposure (MCPAdapter maps schema and name)
262
+ ↓
263
+ Stdio server execution (MCPServer.run() processes requests)
264
+ ```
265
+
266
+ ### Run locally
267
+
268
+ An example MCP server exposing `add` and `greet` tools is included at [basic_mcp_server.py](file:///Users/lakshyachoudhary/My%20Projects/mcptoolforge/examples/basic_mcp_server.py).
269
+
270
+ To start this server over the standard input/output (STDIO) transport:
271
+
272
+ ```bash
273
+ python examples/basic_mcp_server.py
274
+ ```
275
+
276
+ You can connect to this server using any standard MCP client or command-line inspector (such as `@modelcontextprotocol/inspector`).
277
+
278
+ ## End-to-End MCP Verification
279
+
280
+ MCPToolForge's MCP implementation is verified end-to-end through automated integration tests that simulate a complete client-server conversation:
281
+
282
+ 1. **MCP Initialization Handshake**: Establishes protocol compatibility and negotiates capabilities.
283
+ 2. **Tool Discovery (list_tools)**: Allows client to discover registered tools (`add`, `greet`, `failing_tool`, `get_info`), mapping schemas, types, and descriptions accurately.
284
+ 3. **Tool Invocations (call_tool)**: Runs synchronous/asynchronous callables natively and returns outputs (structured data for dict results, and TextContent blocks for other primitive returns).
285
+ 4. **Error Isolation**: Confirms execution exceptions or invalid parameters return cleanly as error results (`is_error=True`) without crashing the active server.
286
+
287
+ To execute the verification suite:
288
+
289
+ ```bash
290
+ python3 -m pytest tests/integration/test_mcp_server.py
291
+ ```
292
+
293
+
294
+ ## Command-Line Interface (CLI)
295
+
296
+ MCPToolForge includes a developer-friendly command-line interface to create, run, and inspect servers with minimal setup:
297
+
298
+ ### Installation
299
+
300
+ Ensure the package is installed:
301
+ ```bash
302
+ pip install mcptoolforge
303
+ ```
304
+
305
+ ### Usage and Help
306
+
307
+ To view all available commands:
308
+ ```bash
309
+ mcptoolforge --help
310
+ ```
311
+
312
+ ### Initialize a Project
313
+
314
+ Create a new working MCP server template in a specified directory:
315
+ ```bash
316
+ mcptoolforge init my-server
317
+ ```
318
+ This generates the following folder structure:
319
+ ```text
320
+ my-server/
321
+ ├── server.py
322
+ ├── pyproject.toml
323
+ ├── README.md
324
+ └── .gitignore
325
+ ```
326
+ *Note: If files already exist in the target directory, `init` will fail safely to prevent accidental overwrites. Use `--force` to overwrite.*
327
+
328
+ ### List Tools
329
+
330
+ Display all registered tools on a server file without starting the transport loops:
331
+ ```bash
332
+ mcptoolforge list --file server.py
333
+ ```
334
+
335
+ ### Inspect Server and Tool Schemas
336
+
337
+ Inspect general server details:
338
+ ```bash
339
+ mcptoolforge inspect --file server.py
340
+ ```
341
+
342
+ Inspect details and input schemas of a specific tool:
343
+ ```bash
344
+ mcptoolforge inspect add --file server.py
345
+ ```
346
+
347
+ ### Run Server
348
+
349
+ Start the MCP transport loops for standard input/output (STDIO) transport:
350
+ ```bash
351
+ mcptoolforge run --file server.py
352
+ ```
353
+
354
+ ## Configuration
355
+
356
+ MCPToolForge projects are configured inside the project's standard `pyproject.toml` file under the `[tool.mcptoolforge]` section. This enables automatic project discovery and streamlines development.
357
+
358
+ ### Configuration Format
359
+
360
+ Here is an example configuration block:
361
+
362
+ ```toml
363
+ [tool.mcptoolforge]
364
+ name = "my-server"
365
+ entrypoint = "server.py"
366
+ transport = "stdio"
367
+ ```
368
+
369
+ ### Configuration Fields
370
+
371
+ - **`name`** (required): The name of your MCP server.
372
+ - **`entrypoint`** (optional, default: `"server.py"`): The relative path to the Python file containing your `MCPServer` instance.
373
+ - **`transport`** (optional, default: `"stdio"`): The transport protocol to use. Currently, only `"stdio"` is supported. Specifying other transport mechanisms (e.g. `"http"`) will produce an error.
374
+
375
+ ### Project Discovery & Resolving Root
376
+
377
+ When you run commands like `mcptoolforge run`, `mcptoolforge list`, or `mcptoolforge inspect` without passing an explicit `--file` argument:
378
+ 1. MCPToolForge starts search from the current working directory (`Path.cwd()`).
379
+ 2. It climbs up parent directories looking for a `pyproject.toml` containing a `[tool.mcptoolforge]` section.
380
+ 3. The directory containing `pyproject.toml` is resolved as the **Project Root**. All relative paths (e.g., `entrypoint`) are resolved relative to this root.
381
+
382
+ ### Entrypoint & Naming Convention
383
+
384
+ When loading the entrypoint module, MCPToolForge looks for a variable named **`server`** that is an instance of `MCPServer`.
385
+ - If the variable `server` is missing, or if it is not an instance of `MCPServer`, an error is raised.
386
+ - If multiple `MCPServer` instances exist in the entrypoint file and none is named `server`, MCPToolForge raises an ambiguity error.
387
+
388
+ ### CLI Precedence & Overrides
389
+
390
+ MCPToolForge resolves the server to load using the following order of precedence:
391
+ 1. Explicit CLI arguments (e.g., `mcptoolforge run --file custom_server.py`)
392
+ 2. Configuration values defined in `pyproject.toml`
393
+ 3. MCPToolForge defaults (`server.py` in current working directory)
394
+
395
+ ### Simplified Workflow
396
+
397
+ With configuration and project discovery in place, you can run and inspect servers with zero boilerplate:
398
+
399
+ ```bash
400
+ # 1. Initialize a new project (includes configuration automatically)
401
+ mcptoolforge init my-server
402
+ cd my-server
403
+
404
+ # 2. Inspect the project details and tools
405
+ mcptoolforge inspect
406
+
407
+ # 3. List the registered tools
408
+ mcptoolforge list
409
+
410
+ # 4. Start the server using stdio transport
411
+ mcptoolforge run
412
+ ```
413
+
414
+ ## Middleware
415
+
416
+ MCPToolForge supports a powerful middleware pipeline that allows you to run cross-cutting concerns (logging, timing, tracing, error handling) around tool execution without modifying your individual tools.
417
+
418
+ ### Defining Middleware
419
+
420
+ To define a middleware, use the `@server.middleware` decorator or register it programmatically via `server.add_middleware()`.
421
+
422
+ ```python
423
+ import logging
424
+ from mcptoolforge import MCPServer
425
+
426
+ logger = logging.getLogger("my_app")
427
+ server = MCPServer("my-server")
428
+
429
+
430
+ # Asynchronous middleware
431
+ @server.middleware
432
+ async def custom_logger(context, next_callable):
433
+ logger.info(f"Invoking {context.tool_name} with args: {context.arguments}")
434
+ try:
435
+ result = await next_callable()
436
+ logger.info(f"Successfully finished {context.tool_name}")
437
+ return result
438
+ except Exception as e:
439
+ logger.error(f"Tool {context.tool_name} failed: {e}")
440
+ raise
441
+ ```
442
+
443
+ > [!CAUTION]
444
+ > **STDIO Logging Safety**: Because standard output (`stdout`) is reserved for standard MCP protocol communication over the STDIO transport, **never** print to stdout inside middleware (e.g. do not use `print()`). Always write logs to standard error (`stderr`) using Python's `logging` module or `sys.stderr`.
445
+
446
+ ### Middleware Execution Order
447
+
448
+ Middlewares execute in the order they are registered:
449
+
450
+ ```text
451
+ Middleware A (before)
452
+ ↓
453
+ Middleware B (before)
454
+ ↓
455
+ Validation & Tool Execution
456
+ ↓
457
+ Middleware B (after)
458
+ ↓
459
+ Middleware A (after)
460
+ ```
461
+
462
+ ### Sync vs Async Middleware
463
+
464
+ MCPToolForge supports both synchronous and asynchronous middlewares:
465
+ - **Async Middleware**: `async def middleware(context, next_callable): ...` — works with both sync and async tools.
466
+ - **Sync Middleware**: `def middleware(context, next_callable): ...` — works with synchronous tools.
467
+ - **Mixed Safety**: To prevent blocking or fragile event loop bridging, a synchronous middleware **cannot** wrap an asynchronous tool or another asynchronous middleware. Violations will raise a `ConfigurationError`.
468
+
469
+ ### Built-in Middlewares
470
+
471
+ MCPToolForge includes pre-packaged middlewares for common workflows:
472
+ - **Timing**: Measures and logs tool execution duration to stderr (`timing_middleware` for async pipelines, `sync_timing_middleware` for purely sync pipelines).
473
+ - **Logging**: Traces tool parameters, entry, and exit statuses (`logging_middleware` for async pipelines, `sync_logging_middleware` for purely sync pipelines).
474
+
475
+ ```python
476
+ from mcptoolforge import MCPServer, timing_middleware, logging_middleware
477
+
478
+ server = MCPServer("demo")
479
+ server.add_middleware(logging_middleware)
480
+ server.add_middleware(timing_middleware)
481
+ ```
482
+
483
+ ### Middleware Context
484
+
485
+ The `MiddlewareContext` object provides the following attributes to inspect tool execution state:
486
+ - `context.tool_name` (str): Name of the tool being executed.
487
+ - `context.tool` (Tool): The registered MCPToolForge Tool object.
488
+ - `context.arguments` (dict): Mutatable inputs passed to the tool.
489
+ - `context.server` (MCPServer): The active server instance.
490
+ - `context.duration` (float | None): MONOTONIC execution time recorded by timing frameworks.
491
+ - `context.error` (Exception | None): Captured exception if execution failed.
492
+
493
+ ---
494
+
495
+ ## Lifecycle Hooks
496
+
497
+ You can register startup and shutdown lifecycle hooks on your MCPServer. These hooks run at server initialization and teardown points (e.g. for database initialization or cleanup).
498
+
499
+ ```python
500
+ @server.on_startup
501
+ async def db_init():
502
+ logger.info("Initializing database...")
503
+
504
+
505
+ @server.on_shutdown
506
+ def db_cleanup():
507
+ logger.info("Cleaning up connections...")
508
+ ```
509
+
510
+ Startup and shutdown hooks support both synchronous and asynchronous functions and will be executed sequentially in the order of registration.
511
+
512
+ ---
513
+
514
+ ## Testing
515
+
516
+ MCPToolForge provides a first-class in-process testing client, `MCPTestClient`, which allows developers to test their tools, resources, and prompts locally without running Claude, Cursor, ChatGPT, or an external MCP client.
517
+
518
+ ### Basic Usage
519
+
520
+ The `MCPTestClient` operates directly against your `MCPServer` instance:
521
+
522
+ ```python
523
+ from mcptoolforge import MCPServer
524
+ from mcptoolforge.testing import MCPTestClient
525
+
526
+ server = MCPServer("demo")
527
+
528
+
529
+ @server.tool
530
+ def add(a: int, b: int) -> int:
531
+ return a + b
532
+
533
+
534
+ def test_add():
535
+ # Sync client usage
536
+ client = MCPTestClient(server)
537
+ result = client.call_tool("add", {"a": 10, "b": 20})
538
+ assert result == 30
539
+ ```
540
+
541
+ ### Lifecycle Hooks
542
+
543
+ If your server configures startup or shutdown hooks, you can use the test client as a context manager to trigger them automatically:
544
+
545
+ ```python
546
+ def test_lifecycle():
547
+ with MCPTestClient(server) as client:
548
+ # startup hooks have run
549
+ assert len(client.list_tools()) == 1
550
+ # shutdown hooks have run
551
+ ```
552
+
553
+ For async tests, use the async context manager:
554
+
555
+ ```python
556
+ async def test_lifecycle_async():
557
+ async with MCPTestClient(server) as client:
558
+ result = await client.call_tool_async("add", {"a": 1, "b": 2})
559
+ assert result == 3
560
+ ```
561
+
562
+ ### Testing Resources
563
+
564
+ To list and read registered resources:
565
+
566
+ ```python
567
+ def test_resources():
568
+ client = MCPTestClient(server)
569
+
570
+ # List resources
571
+ resources = client.list_resources()
572
+ assert len(resources) == 1
573
+ assert resources[0].uri == "config://app"
574
+
575
+ # Read resource
576
+ res_data = client.read_resource("config://app")
577
+ assert "MCPToolForge" in res_data.text
578
+ assert res_data.mime_type == "application/json"
579
+ ```
580
+
581
+ ### Testing Prompts
582
+
583
+ To list and retrieve prompts:
584
+
585
+ ```python
586
+ def test_prompts():
587
+ client = MCPTestClient(server)
588
+
589
+ # List prompts
590
+ prompts = client.list_prompts()
591
+ assert len(prompts) == 1
592
+ assert prompts[0].name == "explain"
593
+
594
+ # Get prompt
595
+ prompt_data = client.get_prompt("explain", {"topic": "MCP"})
596
+ assert len(prompt_data.messages) == 1
597
+ assert prompt_data.messages[0].content == "Explain MCP in simple terms."
598
+ assert prompt_data.messages[0].role == "user"
599
+ ```
600
+
601
+ ### Testing Middleware
602
+
603
+ Middleware layers are executed automatically when invoking tools via the `MCPTestClient`, allowing you to assert that custom logging, timings, or authorization middleware behaves correctly:
604
+
605
+ ```python
606
+ def test_middleware():
607
+ events = []
608
+
609
+ @server.middleware
610
+ def my_middleware(context, next_fn):
611
+ events.append("before")
612
+ res = next_fn()
613
+ events.append("after")
614
+ return res
615
+
616
+ client = MCPTestClient(server)
617
+ client.call_tool("add", {"a": 1, "b": 2})
618
+ assert events == ["before", "after"]
619
+ ```
620
+
621
+ ---
622
+
623
+ ## Development Setup
624
+
625
+ 1. Create and activate a virtual environment:
626
+ ```bash
627
+ python3 -m venv .venv
628
+ source .venv/bin/activate
629
+ ```
630
+
631
+ 2. Install the package in editable mode:
632
+ ```bash
633
+ pip install -e .
634
+ ```
635
+
636
+ 3. Install development dependencies:
637
+ ```bash
638
+ pip install pytest ruff
639
+ ```
640
+
641
+ ## Testing Command
642
+
643
+ To run the unit tests:
644
+ ```bash
645
+ pytest
646
+ ```
647
+
648
+ ## Roadmap
649
+
650
+ - [x] Foundation architecture layout and schema generation
651
+ - [x] Implement local stdio JSON-RPC transport
652
+ - [x] Add CLI interface for installing and executing servers
653
+ - [x] Implement robust runtime argument validation and tool execution
654
+ - [ ] Implement SSE transport for network integration
655
+ - [ ] Integration with MCP-compliant AI environments (e.g. Claude Desktop)
@@ -0,0 +1,37 @@
1
+ mcptoolforge/__init__.py,sha256=o3hkLVXntK-AmyBzdCttsBt8vEXl8RfbIvDcLnAMonY,1791
2
+ mcptoolforge/config.py,sha256=NvLh8V6vJuMvhFFEfqhYL8ycMY3P_onuHSb2qy8WfIQ,1636
3
+ mcptoolforge/decorators.py,sha256=pAYzlX-hZDuvym_n4VkLtKQ4e74jhs4ChdKgad2DOIY,1429
4
+ mcptoolforge/errors.py,sha256=prEVaBGuLcrJUffDJrgClVz21MUWWTCGWncoUdHiOt0,1977
5
+ mcptoolforge/execution.py,sha256=irC0q8lvkNXBQwenIPlb_1kiX0yIWqLT7L2V-4bIGD4,828
6
+ mcptoolforge/project.py,sha256=Cgf1MUwU_58hyvSAifBtQjxJPLVE3voYfqU0WqSpL7Y,5101
7
+ mcptoolforge/registry.py,sha256=lszSHnzcpmopWYnIMpQ7qgmA81oyfwDTpJkpf3olCmw,8027
8
+ mcptoolforge/schema.py,sha256=RnpnnsME-gGAKgg6Pw6Cb6FqmUw1iTS9s2WZLv_zyXg,5170
9
+ mcptoolforge/server.py,sha256=PX-SWldumywhJkxd2E_JKIatK_9Zq0c3z_l19PvRCHw,3312
10
+ mcptoolforge/validation.py,sha256=2r0TgpVIyT0P8gJN-mzA1VgmS3srT8eYGYWxw1_jBY0,8432
11
+ mcptoolforge/cli/__init__.py,sha256=NcJ9OP1qy_3KfbTjH5KxgtndVGgXiN9_adPsuf_LqlI,35
12
+ mcptoolforge/cli/commands.py,sha256=nEj9nXutyJoYdSywYE8Oz0p-XDbGUl3eKjONAUBQKXI,9142
13
+ mcptoolforge/cli/main.py,sha256=gx5xaIR2T6iTUNUhjyfB-xH03GkmcoInUFBrTrCmuWE,2876
14
+ mcptoolforge/mcp/__init__.py,sha256=eSBiR-hMbKef8Ztx46UZjcYpuDzIEmCAUK15BnwEyqI,145
15
+ mcptoolforge/mcp/adapter.py,sha256=VP7Tl5Y1LCpPkIFDIPZx2xfK3o81xoRUHnjU_1WbnuE,16653
16
+ mcptoolforge/mcp/server.py,sha256=_-W_gsIzKVYOAnLusI-RrX0ZhrbZ7Yhdaw7MO0AHJ_w,3896
17
+ mcptoolforge/middleware/__init__.py,sha256=8aZyagWoC1bwj-87iOmkzfGl-0xhGZQVrnOxDz0mBhI,387
18
+ mcptoolforge/middleware/context.py,sha256=B2rRmomXEQvNIBRvSZfT3mVJJdWZ5-Pi0Z0rdXTqXoE,500
19
+ mcptoolforge/middleware/logging.py,sha256=WmNCCz0i6H77YREdEztqTOXiMH8b1FHMN02eziJWG-k,1200
20
+ mcptoolforge/middleware/manager.py,sha256=WmnYlTiuPudOJcYodhIeykRRm_xjnjG7Vws1qrGWP24,2324
21
+ mcptoolforge/middleware/timing.py,sha256=hNGCv5ghFVP5vtYcglIIoBxiEHeWH5N1j9VXSlkKe-o,1441
22
+ mcptoolforge/prompts/__init__.py,sha256=JA9XZG3-_L5GqeKthK3QCvkZfBni8G9mQWcqhivas7o,258
23
+ mcptoolforge/prompts/decorator.py,sha256=qsv5UXYbTRoYpltUhJfInKwrbxi-kIrhhQ7J_7v3OB0,1000
24
+ mcptoolforge/prompts/prompt.py,sha256=5MPb1WK_W6G9ynJC7NduJRVnDXS8A7YUmYRRL6_sUjc,4057
25
+ mcptoolforge/prompts/registry.py,sha256=ZfwYXolODNd6ZRuTWKSR6cHBAWeeTF70iZOb5ToYnlI,1358
26
+ mcptoolforge/resources/__init__.py,sha256=4lO-JWaS5vPNvmaUlIw84p__8ZIu6CU5Dm8DVxPDUgA,242
27
+ mcptoolforge/resources/decorator.py,sha256=9LulIjpD4WPVsrmKS77HiWY-PNKWskhgv9zi9zkroFc,878
28
+ mcptoolforge/resources/registry.py,sha256=KwDG5mv7_yCt5uzXTp2mXLuZEYzBs0qedYTmJvuZ1xU,1483
29
+ mcptoolforge/resources/resource.py,sha256=JbH_W8FQZJxlDLJ1ZdvO_VPs2L63cSgtXUQEYUtss5U,3217
30
+ mcptoolforge/testing/__init__.py,sha256=KmwyquSF5SOw5WQk3g2NeuVV3tLtREoQ6RbAfDTkm5Y,307
31
+ mcptoolforge/testing/client.py,sha256=51rPXMXz3JQT1-wHerlzrQ0nXpOxWmuFkVssUhpuOfI,13684
32
+ mcptoolforge/transports/__init__.py,sha256=DSaZ_tWrdkZ6vn1VZKg39X4qyrez6ByJ9p4acgWccU8,49
33
+ mcptoolforge-0.1.0.dist-info/METADATA,sha256=1lVTwIyZ-fxiA3JLvX7EiJnTnEAeF9I2w7HENRNSo08,21767
34
+ mcptoolforge-0.1.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
35
+ mcptoolforge-0.1.0.dist-info/entry_points.txt,sha256=O5Vv46hrlbt2PCfcDh_6jSzEeqCSEsHWCHVnpxRiBk0,60
36
+ mcptoolforge-0.1.0.dist-info/licenses/LICENSE,sha256=NYhLE7Fh3xystvMjzWhASL6ejS2wpzXVjClMXDLKlSg,1082
37
+ mcptoolforge-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ mcptoolforge = mcptoolforge.cli.main:main