The Testing Academy · Class Notes Sunday, 11 October (IST)
Live class · study guide

Using the Skill Finder MCP from an agent, then Python basics: compiled and interpreted, print, comments, variables, keywords, identifiers and type()

How an agent uses the Skill Finder MCP without MCP Inspector, then the first Python class: why Python is both compiled and interpreted, setting up VS Code with Code Runner, print with sep and end, comments, variables and literals, dynamic typing, keywords, the identifier rules and type(). Files 001 to 015, pushed to the batch repo.

By Pramod Dutta, The Testing Academy. Study notes from the AI Tester Blueprint 4x class, built from the session recording, the batch repository (commit "feat: add chapter 13 MCP notes and chapter 15 Python basics", files 001 to 015, pushed as the class ended) and the Eraser notes deck. The recording begins partway through the class, after the MCP Inspector session; the repo's MCP Inspector notes cover that part. Every Python file was run with Python 3.12, and the output shown is what it prints.

01

What this class covered

  • MCP Inspector versus an agent, and the Skill Finder MCP used from GitHub Copilot
  • Why Python is both compiled and interpreted: source code, bytecode and machine code
  • Setting up: Python, VS Code and the Code Runner extension
  • Comments, print, and print's sep and end options
  • Variables and literals, no semicolons, and strict indentation
  • Dynamic typing and type()
  • Keywords and the rules for identifiers
  • Interview questions: reassignment, BODMAS, multiple assignment, and joining text with a number
  • Tasks: the hello world screenshot, Wednesday's QA battle, Friday's MCP session and the hackathon
02

MCP Inspector versus an agent

The recording picks up at the end of the MCP part of the class, so this is the class's recap. MCP Inspector is a way to see and debug what an MCP server offers, whether it runs locally or over streamable HTTP: its tools, resources and prompts. It is for people. An AI agent does not need it; the agent connects to the MCP server directly. One server can offer any number of tools, resources and prompts.

The MCP Inspector session itself came earlier in the class and is not in the recording. The batch repo's MCP Inspector notes cover it.

03

The Skill Finder MCP, from GitHub Copilot

The Skill Finder MCP came out of the previous class: an MCP server over a library of 100 QA skills, one SKILL.md each, covering the STLC phases, Playwright, API testing, company data and more. The demo showed that an agent uses it with no MCP Inspector in sight:

The connection details for VS Code, from the server's README:

JSON
{ "servers": { "testskill-finder": { "type": "http", "url": "http://127.0.0.1:8110/mcp" } } }
  1. Ask the agent for the connection details and add them to VS Code.
  2. In GitHub Copilot, running DeepSeek V4 Flash, ask: connect with this MCP and tell me about the tools, resources and prompts it offers. The agent connected by itself and reported 13 or more tools, a couple of resources, 3 prompts and 100 skills.
  3. Ask for skills related to Playwright. It found 11.
  4. Ask which skill is best for API testing with Playwright. It picked Playwright API tester, the highest score, and offered to help write a test for the endpoint.

The skills are mostly read, but the server can change them too: two of its tools write.

AN AGENT FINDS THE RIGHT SKILL, NO INSPECTOR NEEDED PROMPT Ask in plain words best skill for API testing with Playwright? AGENT GitHub Copilot connects to the MCP by itself MCP SERVER Skill Finder MCP tools, resources and prompts SKILLS 100 skills one SKILL.md each: STLC, Playwright, API ANSWER Playwright API tester highest score of 11 Playwright skills searches, ranks MCP INSPECTOR For you, not the agent see what a server offers, debug it The agent reported 13+ tools, a few resources, 3 prompts and 100 skills when it connected.
The agent does the connecting and the searching. MCP Inspector is the tool for people who want to look inside a server.

A few people were still unsure what the server is for, so the class used a family: everyone knows how to do something, and you need to find out who can drive. The Skill Finder does that for skills. You describe the task, it finds the one that fits.

Two panels showing the same pegboard of twelve cards, each with a different icon: a cooking pot, a wrench, a paintbrush, a book, a guitar, a steering wheel, a camera, scissors, a hammer, a leaf, a teacup and a globe. Left, titled Who can drive?, with the sublabel 100 skills, one task: a car key with a question-mark tag waits in front of the board. Right, titled Found it, with the sublabel Skill Finder MCP: a magnifying glass highlights the steering wheel card in orange, joined to the key by a dashed line, and the other cards are faded.
Describe the task and the Skill Finder picks out the one skill that fits, the way you would find who in the family can drive.
04

Python is both compiled and interpreted

Python is one of the easiest languages to start with, and the reason to learn it now is practical: with Python you can read and write the code behind LangChain, LangGraph, CrewAI and DeepEval, and build your own agents and MCP servers. It dates from about 1990, older than Java, and it is a human-friendly, high-level language.

Interview question: is Python compiled or interpreted? Both.

The class's picture: two people who do not share a language need a translator, and so do people and a computer, since a CPU does not understand English. A translator can work in two ways: line by line, which is interpretation, or everything in one go, which is compilation.

Two panels with the same small translation machine. Left, titled Line by line, with the sublabel interpreted: a sheet of squiggle text feeds in one strip at a time, translated strips come out one by one, and a circular arrow shows it repeating. Right, titled All at once, with the sublabel compiled: the whole sheet goes in and a finished bound booklet comes out in one go.
Interpretation translates as it goes; compilation translates everything first. Python does the second, then the first.

Python uses both, one after the other:

  • Source code is what you write in a .py file. People can read it; the CPU cannot.
  • Bytecode is an in-between code. Python compiles your whole file into bytecode first. You never see it while running a file.
  • Machine code, also called native code, is what the CPU runs. The Python Virtual Machine works through the bytecode one instruction at a time, which is the interpreted part.
HOW PYTHON RUNS hello.py: BOTH COMPILED AND INTERPRETED SOURCE hello.py you write it, people read it COMPILE Compiler the whole file, before it runs BYTECODE Bytecode in between: no CPU runs it INTERPRET Python VM one instruction at a time MACHINE CPU machine code, 0s and 1s compiled: source to bytecode, all at once interpreted: line by line Run hello.py directly and the bytecode stays in memory. Import it from another file and Python saves it: __pycache__/hello.cpython-312.pyc
Why the interview answer is "both": the compile step happens first and all at once, then the Python Virtual Machine works through the bytecode instruction by instruction.

In class, hello.py was described as becoming hello.pyc. Python does compile every file to bytecode, but it only saves a .pyc file for modules that get imported. Run hello.py directly and nothing is written; import it from another file and Python saves __pycache__/hello.cpython-312.pyc, where 312 is the Python version.

05

Setting up: Python, VS Code and Code Runner

  • Install Python. Download the latest release, Python 3.15.0, from python.org. Any 3.x version works; the class machine had 3.13. Check it in a terminal with python --version (python3 --version on a Mac).
  • Use VS Code, which supports Python out of the box.
  • Install the Code Runner extension. Search for it under Extensions and install it. It adds a Run button, with no environment variables to set.
  • Or run from the terminal: python followed by the file name.
Python
print("Hello TheTestingAcademy")
Text
Hello TheTestingAcademy
06

Comments and print

A line that starts with # is a comment: Python skips it. Comment out a print and nothing is printed.

Python
# print("Hello TheTestingAcademy")

# This is Comment
# This code will not be executed.
#
print(2 + 2)
print(2, 3, 4)
print("Hello", True, "PrrammodDutta", 12342)
Text
4
2 3 4
Hello True PrrammodDutta 12342

print can take a calculation, or any number of comma-separated values of any type. Hover over print in VS Code and the signature starts with *values: the star means any number of values.

Two options control the layout:

  • sep is what goes between the values. The default is a space; the class used *, __ and -.
  • end is what goes after the last value. The default is a new line, \n. With end="\t", the next print continues on the same line after a tab.
Python
print("Hello", "World")
print("Hello", "World", "TheTestingAcademy", sep="*")
print("Hello", "World", "TheTestingAcademy", sep="__")


print("*", "*", sep="-", end="\t")
print("*", "*", sep="_")
Text
Hello World
Hello*World*TheTestingAcademy
Hello__World__TheTestingAcademy
*-* *_*

\n and \t are escape characters, a backslash followed by a letter: a new line and a tab.

07

Variables, literals and dynamic typing

A variable is a container that holds a value. In a = 10, the name a is the identifier, and 10 is the value, also called the literal. You can change the value later.

  • No semicolons. Python statements end at the end of the line.
  • Indentation is strict. Wrong spaces or tabs and the program will not run; it fails with an indentation error. Right-click and choose Format Document to tidy it.
  • No data type is written. Python works it out from the value.
A NAME, A VALUE, AND A TYPE PYTHON WORKS OUT age = 41 IDENTIFIER the name the label on the container OPERATOR assignment puts the value into the name LITERAL the value written straight into the code TYPE int worked out by Python, never declared Dynamically typed the same name can take a value of another type (file 008) VALUE, THEN ITS TYPE age = 98 <class 'int'> VALUE, THEN ITS TYPE age = "Pramod" <class 'str'> VALUE, THEN ITS TYPE age = True <class 'bool'>
No type is written anywhere: Python reads it from the value, and type() tells you what it decided. Assign a new value and the type can change with it.

Python is dynamically typed: the same name can hold a number now and a string later, and the interpreter adjusts. The class contrasted this with Java, where it is not allowed.

Python
age = 65
age = "Pramod"
# Dynamic Typed Language. - It can understand you are doing, want.
print(age)
pi = 3.14
name = "Pramod"
name = "Pramod"
name = "Pramod"
name = "Pramod"
name = "Pramod"
name = "Dutta"
print(name)
Text
Pramod
Dutta
Python
# Dynamically typed

age = 98
print(type(age))
age = "Pramod"
print(type(age))
age = True
print(type(age))
Text
<class 'int'>
<class 'str'>
<class 'bool'>

type() tells you what Python decided. It uses short names: str for strings, float, bool. Python also has complex numbers, written with j; the class showed them for completeness, and they are not used in automation or AI work.

Python
_pramod = "amit"
_abc = 23
pi = 3.14
name = "Pramod"
isMale = True

# Type
print(type(_pramod))
print(type(pi))
print(type(isMale))

complex_number = 2 + 3j
print(complex_number)
print(complex_number.real)
print(complex_number.imag)
print(type(complex_number))
Text
<class 'str'>
<class 'float'>
<class 'bool'>
(2+3j)
2.0
3.0
<class 'complex'>

The data types Python offers, as listed in class:

Group Types
Numbers int, float, complex, and bool for True and False
Text str, a bunch of characters
Collections list, tuple, set, frozenset, dict
Binary bytes and related types

Python has no "map": its key-value type is the dictionary, dict.

08

Keywords

A keyword is a reserved word with a fixed meaning, so you cannot use it as a variable name: class = 10 fails with SyntaxError: invalid syntax. To list them, import the keyword module and print keyword.kwlist:

Python
a = 10
a = 4.5
a = "pramod"

# print()
# class
# None
# break

import keyword
print(keyword.kwlist)
Text
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']

That is 35 keywords. Python is case-sensitive, keywords included: print works and Print fails with NameError: name 'Print' is not defined. Only False, None and True start with a capital letter.

In class, function = 10 was called invalid alongside class = 10. It is valid: function is not a Python keyword, as the list above shows. Python defines functions with def, and def = 10 would fail. Running function = 10; print(function) prints 10.

09

Rules for identifiers

Python
age = 65
_age = 65
print(age)
print(_age)

_ = 12
print(_)
_ = _ + 1
print(_)

# 123abc = 90
abc123 = "abc123"
print(abc123)
Text
65
65
12
13
abc123
Python
long_var_name_is_created_here = "Hello"
print(long_var_name_is_created_here)
Text
Hello

The rules, from the class's rules file:

Rule Valid Invalid
Letters, digits and underscores only first_name, abc123 first-name, first name, total$
Cannot start with a digit abc123 123abc
Cannot be a keyword class_name class, for
Case-sensitive age and Age are two names
No length limit long_var_name_is_created_here
A single underscore is a name _ = 12
Avoid built-in names items = [1, 2, 3] list = [1, 2, 3] works, then list() breaks
10

Interview questions

1. What does this print? c is set to a + b, then reassigned.

Python
a = 10
b = 10
c = a + b
print(c)
c = c - 10
print(c)
Text
20
10

2. What is 10 + 34 * 3 - 1? Apply BODMAS: multiplication before addition and subtraction, so 34 * 3 = 102, then 10 + 102 - 1 = 111.

Python
a = 10 + 34 * 3 - 1
print(a)


# BODMAS
#
# BODMAS is an acronym that helps remember the order of operations in mathematics:
# B: Brackets
# O: Order of powers or roots
# D: Division
# M: Multiplication
# A: Addition
# S: Subtraction
Text
111

3. Can you assign several variables in one line? Yes. Each name takes the value in the same position.

Python
a, b, c = 45, 5.4, "pramod"
print(a)
print(b)
print(c)
Text
45
5.4
pramod

4. Can you join a string and a number? Not in Python. Two strings join with +, but a string plus a number is an error. Java and JavaScript would turn the number into text; Python refuses.

Python
print("Amit", "Teja", "Tushar")

print("PRAMOD" + "DUTTA")

# Detonation between the string and integer is not allowed in 
print("PRAMOD" + 10 + 20)
Text
Amit Teja Tushar
PRAMODDUTTA
Traceback (most recent call last):
  File "chapter_15_Python_PyTest/ex_02_Keywords_Identifier_Literals/013_MathIQ.py", line 6, in <module>
    print("PRAMOD" + 10 + 20)
          ~~~~~~~~~^~~~
TypeError: can only concatenate str (not "int") to str

The fix is to convert the number yourself with str():

Python
# print("Hello" + 15)
print("Hello" + str(15))
Text
Hello15

max() and min() are built-in functions that take any number of arguments:

Python
result = max(3, 4, 5, 100, 101)
print(result)


result_min = min(3, 4)
print(result_min)


result = max(3, 4, 67, -1, 190, 999, 100000, 9899, -1)
print(result)
Text
101
3
100000
11

Tasks and announcements

  • This week stays slow so the basics settle; Python picks up speed next week.
  • Wednesday: a QA battle, or a test. It opens at 7 AM and closes at 7 PM, or around 10 PM: 12 hours to finish. It covers what has been taught so far: RAG, MCP, LLM basics, n8n and Langflow.
  • Friday evening: an advanced MCP session, with certification. Details are coming; plan to join.
  • A hackathon this month. Build a QA solution with RAG, MCP, AI agents, n8n or Langflow, aiming at open-source tools for testers. The prize money has gone up, as far as your full fee back, and everyone who takes part gets a certificate. A teaser is on its way.

Task 1, hello world. Install Python and Code Runner, run a hello world program, and post a screenshot of it running in the SDET Club chat, in the same comment thread.

Task 2, Wednesday's QA battle. Finish it within the 12 hours.