You may create a new tag simply by doing a package_create() or package_update() and specifying a tag that doesn't exist yet, and I think (guessing) the correct format for the "tags" param to package_create() or package_update() should be:
"tags": [{"name": "my_tag"}, {"name": "my-other-tag"}]
But you would have to test that.
However that complains that it wants tags in dictionary format, as I would use for specifying tags that are part of a vocabulary. How do I specify a free tag?
So as above, just the same dictionary format as for a vocab tag but with only the "name" key and no "vocabulary_id".
Also, what is the best way to access the tags once I have them entered? I ran into a situation where my_package.package_tags contained a tag, but my_package.get_tags() returned an empty list?
Use the action functions: package_show(), tag_list(), tag_show(), etc.
If you're writing a CKAN extension and you don't want to call CKAN's action functions by making HTTP requests, then you should interact with CKAN using the "plugins toolkit" which includes a way to call action functions like this:
import ckan.plugins.toolkit as tk
my_package = tk.get_action('package_show')({'id': 'my_package'})
You'll find lots of other useful stuff in the toolkit.