Ping

Ping Connect (🏁 solution)
👨‍💼 Great job! Now we know we've got an MCP server up and running. From here we can start adding a bunch of different tools, resources, and more to it.
🦉 What the StdioServerTransport does
The StdioServerTransport is a simple transport that allows you to connect to your MCP server using the command line. It's a good way to get started and understand how MCP servers work.
The MCP Client takes the command and args you configure and spawns a child process:
import { spawn } from 'child_process'

// these come from our config in the MCP Inspector:
const command = 'npm'
const args = [
	'--silent',
	'--prefix',
	'/Users/kody/code/mcp-fundamentals',
	'run',
	'dev:mcp',
]

// Then the MCP client spawns a child process:
const child = spawn(command, args)
Once started, the client and server communicate by sending and receiving messages through standard input and output (stdio). These messages follow the JSON-RPC format, which is a standard way to structure requests and responses.

Example: Ping Request and Response

Suppose the client wants to check if the server is running. It sends a ping request to the server by writing a line of JSON to the server's standard input:
{ "jsonrpc": "2.0", "id": "123", "method": "ping" }
The server reads this line from its standard input, processes the request, and writes a response to its standard output:
{ "jsonrpc": "2.0", "id": "123", "result": {} }
This is a typical request-response cycle:
  • The client writes a request (like ping) to the server's stdin.
  • The server reads the request, processes it, and writes a response to stdout.
  • The client reads the response from the server's stdout.
Here's a simplified TypeScript example of how this might look in code:
// Client sends a ping request
child.stdin.write(
	JSON.stringify({ jsonrpc: '2.0', id: '123', method: 'ping' }) + '\n',
)

// Client listens for the response
child.stdout.on('data', (data) => {
	console.log('Received from server:', data.toString())
	// Should log: {"jsonrpc": "2.0", "id": "123", "result": {}}
})
Note: Each message is typically sent as a single line of JSON, so a newline character (\n) is used to separate messages.

⚠️ What happens if you use console.log for logging?

If your server uses console.log for regular logging, those log messages will be sent to standard output (stdout) along with your protocol messages. This can confuse the client, which expects only valid JSON-RPC messages on stdout.
For example, if your server does this:
console.log('Server started!')
Then the output on stdout might look like:
Server started!
{"jsonrpc": "2.0", "id": "123", "result": {}}
When the client tries to read and parse the response, it will encounter the plain text Server started! and likely throw a parsing error, because it expects only JSON.
That's why you should use console.error for logging and debugging output. Standard error (stderr) is separate from stdout, so log messages won't interfere with the protocol communication.
Other transport mechanisms exist as well, and while the code for them is different the underlying concept is the same: a server and client communicating with each other using a standard protocol.

Please set the playground first

Loading "Ping"
Loading "Ping"