Part 2 - MCP Client Setup in 10 Minutes

Jack HerringtonAbout 5 min readJun 3, 2025Watch original
THE SUMMARYAI-generated

DIY MCP Client: A Deep Dive Summary

Key Concepts:

  • MCP (Managed Component Protocol): A protocol for communication between applications, enabling them to expose and consume functionalities (tools and resources).
  • Standard IO (stdio): A communication channel using standard input, output, and error streams.
  • JSON-RPC: A remote procedure call protocol encoded in JSON.
  • Tools: Functionalities exposed by an MCP server that can be invoked by a client.
  • Resources: Data or information exposed by an MCP server that can be accessed by a client.
  • Notifications: Asynchronous messages sent from client to server without expecting a response.

1. Setting up the MCP Client

  • Objective: To create an MCP client from scratch using Node.js built-in libraries, mirroring the DIY MCP server created in the previous episode.
  • Initial Setup:
    • Create a client.ts file in the client directory.
    • Import spawn from node:child_process to run the MCP server locally.
    • Create an async main function to use await and encapsulate the application logic.
  • Spawning the Server:
    • Use spawn('node', ['../server/dist/index.js']) to start the DIY MCP server.
    • Configure stdio to use pipes for bidirectional communication:
      • stdin: 'pipe'
      • stdout: 'pipe'
      • stderr: 'inherit'
  • Readline Interface:
    • Import readline from node:readline.
    • Create a readline interface: readline.createInterface({ input: serverProcess.stdout }). This allows reading JSON messages sent by the server line by line.

2. Sending Messages to the Server

  • send Function: An async function to send MCP messages to the server.
    • Takes method (e.g., "initialize", "tools/list"), params (parameters for the method), and isNotification (boolean) as arguments.
    • Constructs a JSON-RPC message:
      {
        "jsonrpc": "2.0",
        "method": method,
        "params": params,
        "id": id // Only if not a notification
      }
      
    • Sends the message to the server's stdin using serverProcess.stdin.write(JSON.stringify(message) + '\n').
    • If isNotification is true, the function returns immediately.
    • If isNotification is false, the function uses readlineInterface.question() to wait for a response from the server.
    • Parses the JSON response and returns the result field.

3. Initializing the MCP Server

  • Sending the "initialize" Method:
    • Call the send function with the "initialize" method.
    • Provide parameters such as the protocol version, client capabilities (empty in this case), and client information (name and version).
    • Example:
      const response = await send("initialize", {
        "protocolVersion": "1.0",
        "capabilities": {},
        "clientInfo": {
          "name": "DIY client",
          "version": "1.0"
        }
      }, false);
      console.log(response);
      
  • Verifying Communication: The response from the server should include information about available tools and resources.
  • Testing with UVX MCP Server Fetch: The client is tested against an existing MCP server ("UVX MCP server fetch") to ensure compatibility.
  • Sending the "initialized" Notification:
    • After receiving the server's response to "initialize", send the "initialized" notification to indicate that the client is ready.
    • await send("initialized", {}, true);

4. Interacting with Tools and Resources

  • Determining Server Capabilities:
    • Extract server information (name, version) and capabilities (tools, resources) from the "initialize" response.
  • Fetching Tool and Resource Lists:
    • If the server supports tools (indicated by the "tools" capability), call the "tools/list" method to retrieve the list of available tools.
    • If the server supports resources (indicated by the "resources" capability), call the "resources/list" method to retrieve the list of available resources.
  • Data Structures:
    • Tool interface: { name: string; description: string; inputSchema: any; }
    • Resource interface: { uri: string; name: string; }
  • Using Clack Prompts and Chalk for User Interface:
    • Import intro, select, text, and isCancel from clack.
    • Import chalk for colorization.
    • Use intro to display a welcome message with server information.
  • Main Interaction Loop:
    • An infinite loop presents the user with options to "Run a tool" or "Get a resource".
    • Use select to present the options.
    • If the user cancels (Ctrl+C), exit the process.

5. Handling Tools

  • Selecting a Tool:
    • If the user chooses "Run a tool", use select to present a list of available tools.
    • The options are generated from the tools array, with the tool name as the label.
  • Prompting for Arguments:
    • For the selected tool, iterate through the inputSchema.properties to identify required parameters.
    • Use text from clack to prompt the user for each parameter value.
    • Store the arguments in an args object.
  • Calling the Tool:
    • Call the send function with the tool name as the method and the args object as the parameters.
    • Example: await send(selectedTool.name, args, false);
  • Displaying the Result:
    • Use a dumpContent function to display the tool's output.
    • The dumpContent function handles both JSON and plain text output.

6. Handling Resources

  • Selecting a Resource:
    • If the user chooses "Get a resource", use select to present a list of available resources.
    • The options are generated from the resources array, with the resource name as the label.
  • Reading the Resource:
    • Call the send function with the "resources/read" method and the resource URI as the parameter.
    • Example: await send("resources/read", { uri: selectedResource.uri }, false);
  • Displaying the Resource Content:
    • Use the dumpContent function to display the resource content.

7. Testing with UVX MCP Server Fetch (Again)

  • The client is tested again with the "UVX MCP server fetch" to demonstrate its ability to interact with different MCP servers.
  • The example uses the JSONPlaceholder API to fetch data.

8. Conclusion

  • The video demonstrates how to build a DIY MCP client from scratch using Node.js built-in libraries.
  • The client can communicate with both the DIY MCP server and other MCP servers, such as "UVX MCP server fetch".
  • The client supports calling tools, retrieving resources, and handling user input.
  • The next video will explore integrating AI with the MCP client to enable AI agents to access and utilize MCP tools.

AI summaries can miss context or contain errors. Check important details against the original video.

Go a little deeper.

Have a question about this video? Load its transcript to open the video chat.