# How to Integrate Third-Party Tools into MCP Definitions: A Complete Guide

> Learn to integrate third-party tools into MCP definitions. Discover how to declare tools, implement handlers, and execute external binaries in this complete guide.

- Repository: [Martin Vogel/codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp)
- Tags: how-to-guide
- Published: 2026-07-03

---

**To integrate third-party tools into MCP definitions, declare the tool in the static `TOOLS` array in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c), implement a handler function that parses JSON arguments and executes the external binary, and wire the handler into the `cbm_mcp_handle_tool` dispatch switch.**

The **Memory-Code-Protocol (MCP)** server in the `DeusData/codebase-memory-mcp` repository exposes a set of tools callable via JSON-RPC. Adding third-party tools follows the same pattern used for built-in tools like `search_graph` and `manage_adr`. This guide walks you through the three-step integration process using actual source code from the repository.

## Step 1: Declare the Tool in the Static TOOLS Table

Every MCP tool must be registered in the static array `TOOLS` located in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c) (lines 11–31). This declaration supplies the metadata required for tool discovery and JSON validation.

### Understanding the TOOLS Array Structure

The `TOOLS` array contains `tool_def_t` structures with four fields: the tool name, human-readable title, description, and a JSON Schema string defining the input arguments. Here is how to add a new third-party tool:

```c
static const tool_def_t TOOLS[] = {
    {"search_graph", "Search graph", "Search the code knowledge graph …",
     "{\"type\":\"object\",\"properties\":{ … },\"required\":[\"project\"]}"},
    /* … existing entries … */
    {"my_third_party", "My Third‑Party Tool",
     "Runs a third‑party binary and returns its stdout as JSON.",
     "{\"type\":\"object\",\"properties\":{"
     "\"project\":{\"type\":\"string\"},"
     "\"binary_path\":{\"type\":\"string\",\"description\":\"Path to the executable\"},"
     "\"args\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}}"
     "},\"required\":[\"project\",\"binary_path\"]}"}
};

```

### JSON Schema Definition

The `input_schema` field uses **JSON Schema** to define the tool's interface. This schema automatically generates CLI flags and validates incoming RPC arguments. The `name` field (`"my_third_party"`) becomes the identifier used by clients in `tools/list` and `list_tools` calls.

## Step 2: Implement the Handler Function

Create a static function following the standard handler signature used throughout [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c). The function receives the server context and a JSON string of arguments, then returns a formatted MCP response.

### Handler Function Signature

All handlers follow this pattern:

```c
static char *handle_my_third_party(cbm_mcp_server_t *srv, const char *args) {
    /* Implementation */
}

```

### Argument Parsing and Validation

Extract arguments using the MCP helper functions. As shown in the `handle_manage_adr` implementation (lines 81–99), use `cbm_mcp_get_string_arg` for string values and `cbm_mcp_get_arguments` for complex structures:

```c
static char *handle_my_third_party(cbm_mcp_server_t *srv, const char *args) {
    char *project   = get_project_arg(args);
    char *binary    = cbm_mcp_get_string_arg(args, "binary_path");
    char *argv_json = cbm_mcp_get_arguments(args);

    if (!project || !binary) {
        char *err = cbm_mcp_text_result("{\"error\":\"missing arguments\"}", true);
        free(project); free(binary); free(argv_json);
        return err;
    }
    /* … */
}

```

### Process Execution and Output Capture

Execute the third-party binary using `fork/exec` or a library wrapper. The example below constructs an argument array from the JSON input, prepends the binary path, and captures stdout:

```c
    /* Resolve project store if needed */
    cbm_store_t *store = resolve_store(srv, project);
    if (!store) { /* handle error */ }

    /* Build argv array */
    int argc = 0;
    char **argv = NULL;
    if (argv_json) {
        argv = json_array_to_argv(argv_json, &argc);
    }
    argv = prepend_binary(binary, argv, &argc);

    /* Execute and capture output */
    char *output = run_process_and_capture_stdout(binary, argv, argc);
    free_argv(argv);
    free(argv_json);

```

### Formatting the MCP Response

Wrap results using `cbm_mcp_text_result` (implemented in lines 45–73). This function creates the required MCP text envelope containing your JSON payload:

```c
    yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
    yyjson_mut_val *root = yyjson_mut_obj(doc);
    yyjson_mut_doc_set_root(doc, root);
    yyjson_mut_obj_add_strcpy(doc, root, "stdout", output ? output : "");
    yyjson_mut_obj_add_str(doc, root, "status", output ? "ok" : "error");
    char *json = yy_doc_to_str(doc);
    yyjson_mut_doc_free(doc);
    free(output);
    free(project);
    free(binary);

    return cbm_mcp_text_result(json, false);   // false indicates success
}

```

## Step 3: Wire the Handler into the Dispatch Switch

The central dispatcher `cbm_mcp_handle_tool` (lines 511–518) routes incoming requests to the appropriate handler. Add a new conditional branch that matches your tool name and forwards the call:

```c
char *cbm_mcp_handle_tool(cbm_mcp_server_t *srv,
                          const char *tool_name,
                          const char *args_json) {
    /* … existing branches … */
    if (strcmp(tool_name, "my_third_party") == 0) {
        return handle_my_third_party(srv, args_json);
    }
    /* … fallback error handling … */
    snprintf(msg, sizeof(msg), "unknown tool: %s", tool_name);
    return cbm_mcp_text_result(msg, true);
}

```

This pattern matches the existing implementations for `manage_adr` and `search_graph`, ensuring consistency across the codebase.

## Testing and Validation

After modifying [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c), add unit tests in [`tests/test_mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/tests/test_mcp.c) following the existing framework. Create test cases that invoke `cbm_mcp_handle_tool` with mock binaries and assert that the returned MCP envelope contains the expected `stdout` and `status` fields.

Update documentation by adding a markdown entry in [`README.md`](https://github.com/DeusData/codebase-memory-mcp/blob/main/README.md) describing the tool's purpose and flags. The description and schema you added to `TOOLS` automatically surface in `list_tools` responses, but explicit documentation helps users understand the external dependencies.

## Example Usage

Once recompiled, invoke the tool via the CLI. The interface automatically constructs the JSON payload from the schema definition:

```bash
codebase-memory-mcp cli my_third_party \
  --binary_path /usr/local/bin/example_tool \
  --args '[ "arg1", "--flag", "value" ]' \
  --project my_repo

```

The MCP server returns a standardized envelope:

```json
{
  "content": [
    {"type":"text","text":"{\"stdout\":\"example output\\n\",\"status\":\"ok\"}"}
  ],
  "isError": false
}

```

## Summary

- **Declare** the tool in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c) by adding an entry to the static `TOOLS` array with a JSON Schema defining the input arguments.
- **Implement** a handler function that extracts arguments using `cbm_mcp_get_string_arg`, executes the third-party binary, and formats results with `cbm_mcp_text_result`.
- **Register** the handler in `cbm_mcp_handle_tool` by adding a `strcmp` branch that maps the tool name to your handler.
- **Test** the integration using the framework in [`tests/test_mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/tests/test_mcp.c) and update [`README.md`](https://github.com/DeusData/codebase-memory-mcp/blob/main/README.md) with usage examples.

## Frequently Asked Questions

### What is the MCP protocol in DeusData/codebase-memory-mcp?

The **Memory-Code-Protocol (MCP)** is a JSON-RPC interface exposed by the `codebase-memory-mcp` server that allows agents to query and manipulate code knowledge graphs. It defines a standard tool-calling pattern where clients send tool names and JSON arguments, and the server returns structured text responses wrapped in MCP envelopes.

### Can I integrate third-party tools as shared libraries instead of executables?

Yes. While the examples show `fork/exec` patterns for binaries, you can link against shared libraries directly within your handler function. Replace the `run_process_and_capture_stdout` call with direct function calls to the library API, then format the results using the same `cbm_mcp_text_result` wrapper to maintain protocol compatibility.

### How do I handle errors when a third-party binary fails?

Return an error response using `cbm_mcp_text_result` with the second parameter set to `true`. Capture the exit code or stderr from the failed process, construct a JSON error object containing diagnostic information, and pass it to `cbm_mcp_text_result`. This signals to MCP clients that the tool execution failed while preserving the structured error details.

### Where should I add tests for new MCP tools?

Add test cases to [`tests/test_mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/tests/test_mcp.c) following the existing test style. Create mock binaries that print predictable output, then call `cbm_mcp_handle_tool` with the tool name and verify that the returned string contains the expected JSON structure. Test both successful execution paths and error conditions, such as missing required arguments or non-existent binary paths.